1
0
mirror of https://github.com/regclient/regclient.git synced 2025-08-10 02:02:44 +03:00
Files
regclient/types/blob/tar.go
Brandon Mitchell cf07a3cc0c Adding diff and regctl cmds to compare manifests and blobs
Signed-off-by: Brandon Mitchell <git@bmitch.net>
2022-07-24 11:51:23 -04:00

103 lines
2.2 KiB
Go

package blob
import (
"archive/tar"
"fmt"
"io"
"io/ioutil"
"github.com/opencontainers/go-digest"
"github.com/regclient/regclient/pkg/archive"
)
// TarReader reads or writes to a blob with tar contents and optional compression
type TarReader interface {
Blob
io.Closer
GetTarReader() (*tar.Reader, error)
}
type tarReader struct {
common
origRdr io.Reader
reader io.Reader
digester digest.Digester
tr *tar.Reader
}
// NewTarReader creates a TarReader
func NewTarReader(opts ...Opts) TarReader {
bc := blobConfig{}
for _, opt := range opts {
opt(&bc)
}
c := common{
desc: bc.desc,
r: bc.r,
rawHeader: bc.header,
resp: bc.resp,
}
tr := tarReader{
common: c,
origRdr: bc.rdr,
}
if bc.rdr != nil {
tr.blobSet = true
tr.digester = digest.Canonical.Digester()
tr.reader = io.TeeReader(bc.rdr, tr.digester.Hash())
}
return &tr
}
// Close attempts to close the reader and populates/validates the digest
func (tr *tarReader) Close() error {
var err error
if tr.digester != nil {
dig := tr.digester.Digest()
tr.digester = nil
if tr.desc.Digest.String() != "" && dig != tr.desc.Digest {
err = fmt.Errorf("digest mismatch, expected %s, received %s", tr.desc.Digest.String(), dig.String())
}
tr.desc.Digest = dig
}
if tr.origRdr == nil {
return err
}
// attempt to close if available in original reader
if trc, ok := tr.origRdr.(io.Closer); ok {
return trc.Close()
}
return err
}
// GetTarReader returns the tar.Reader for the blob
func (tr *tarReader) GetTarReader() (*tar.Reader, error) {
if tr.reader == nil {
return nil, fmt.Errorf("blob has no reader defined")
}
if tr.tr == nil {
dr, err := archive.Decompress(tr.reader)
if err != nil {
return nil, err
}
tr.tr = tar.NewReader(dr)
}
return tr.tr, nil
}
// RawBody returns the original body from the request
func (tr *tarReader) RawBody() ([]byte, error) {
if !tr.blobSet {
return []byte{}, fmt.Errorf("Blob is not defined")
}
if tr.tr != nil {
return []byte{}, fmt.Errorf("RawBody cannot be returned after TarReader returned")
}
b, err := ioutil.ReadAll(tr.reader)
if err != nil {
return b, err
}
err = tr.Close()
return b, err
}