diff --git a/ipld/car/v2/blockstore/doc.go b/ipld/car/v2/blockstore/doc.go index c2cf62a80..ddbcc98e6 100644 --- a/ipld/car/v2/blockstore/doc.go +++ b/ipld/car/v2/blockstore/doc.go @@ -3,10 +3,9 @@ // // The ReadOnly blockstore provides a read-only random access from a given data payload either in // unindexed v1 format or indexed/unindexed v2 format: -// - ReadOnly.ReadOnlyOf can be used to instantiate a new read-only blockstore for a given CAR v1 -// data payload and an existing index. See index.Generate for index generation from CAR v1 -// payload. -// - ReadOnly.OpenReadOnly can be used to instantiate a new read-only blockstore for a given CAR v2 +// * ReadOnly.NewReadOnly can be used to instantiate a new read-only blockstore for a given CAR v1 +// or CAR v2 data payload with an optional index override. +// * ReadOnly.OpenReadOnly can be used to instantiate a new read-only blockstore for a given CAR v2 // file with automatic index generation if the index is not present in the given file. This // function can optionally attach the index to the given CAR v2 file. // diff --git a/ipld/car/v2/blockstore/readonly.go b/ipld/car/v2/blockstore/readonly.go index 521f30280..4125cc1aa 100644 --- a/ipld/car/v2/blockstore/readonly.go +++ b/ipld/car/v2/blockstore/readonly.go @@ -42,10 +42,47 @@ type ReadOnly struct { carv2Closer io.Closer } -// ReadOnlyOf opens ReadOnly blockstore from an existing backing containing a CAR v1 payload and an existing index. -// The index for a CAR v1 payload can be separately generated using index.Generate. -func ReadOnlyOf(backing io.ReaderAt, index index.Index) *ReadOnly { - return &ReadOnly{backing: backing, idx: index} +// NewReadOnly creates a new ReadOnly blockstore from the backing with a optional index as idx. +// This function accepts both CAR v1 and v2 backing. +// The blockstore is instantiated with the given index if it is not nil. +// +// Otherwise: +// * For a CAR v1 backing an index is generated. +// * For a CAR v2 backing an index is only generated if Header.HasIndex returns false. +// +// There is no need to call ReadOnly.Close on instances returned by this function. +func NewReadOnly(backing io.ReaderAt, idx index.Index) (*ReadOnly, error) { + version, err := carv2.ReadVersion(internalio.NewOffsetReader(backing, 0)) + if err != nil { + return nil, err + } + switch version { + case 1: + if idx == nil { + if idx, err = index.Generate(backing); err != nil { + return nil, err + } + } + return &ReadOnly{backing: backing, idx: idx}, nil + case 2: + v2r, err := carv2.NewReader(backing) + if err != nil { + return nil, err + } + if idx == nil { + if v2r.Header.HasIndex() { + idx, err = index.ReadFrom(v2r.IndexReader()) + if err != nil { + return nil, err + } + } else if idx, err = index.Generate(backing); err != nil { + return nil, err + } + } + return &ReadOnly{backing: v2r.CarV1Reader(), idx: idx}, nil + default: + return nil, fmt.Errorf("unsupported car version: %v", version) + } } // OpenReadOnly opens a read-only blockstore from a CAR v2 file, generating an index if it does not exist. diff --git a/ipld/car/v2/blockstore/readwrite.go b/ipld/car/v2/blockstore/readwrite.go index 99fd11d2a..cf10a7750 100644 --- a/ipld/car/v2/blockstore/readwrite.go +++ b/ipld/car/v2/blockstore/readwrite.go @@ -88,7 +88,7 @@ func NewReadWrite(path string, roots []cid.Cid, opts ...Option) (*ReadWrite, err } b.carV1Writer = internalio.NewOffsetWriter(f, int64(b.header.CarV1Offset)) carV1Reader := internalio.NewOffsetReader(f, int64(b.header.CarV1Offset)) - b.ReadOnly = *ReadOnlyOf(carV1Reader, idx) + b.ReadOnly = ReadOnly{backing: carV1Reader, idx: idx} if _, err := f.WriteAt(carv2.Pragma, 0); err != nil { return nil, err }