func seekReader(r io.Reader, offset, size int64) (io.Reader, error) {
	seeker, ok := r.(io.Seeker)
	if ok {
		nn, err := seeker.Seek(offset, io.SeekStart)
		if nn != offset {
			return nil, errors.Wrapf(err, "failed to seek to offset %v", offset)
		}
		if err != nil {
			return nil, err
		}
		return r, nil
	}
	readerAt, ok := r.(io.ReaderAt)
	if ok && size > offset {
		sr := io.NewSectionReader(readerAt, offset, size)
		return sr, nil
	}
	n, err := copyWithBuffer(ioutil.Discard, io.LimitReader(r, offset))
	if err != nil {
		return nil, errors.Wrap(err, "failed to discard to offset")
	}
	if n != offset {
		return nil, errors.Errorf("unable to discard to offset")
	}
	return r, nil
}
seekReader attempts to seek the reader to the given offset, either by
resolving `io.Seeker`, by detecting `io.ReaderAt`, or discarding
up to the given offset.
package content
import (
	"context"
	"io"
	"io/ioutil"
	"math/rand"
	"sync"
	"time"
	"github.com/containerd/containerd/errdefs"
	"github.com/opencontainers/go-digest"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
)
var bufPool = sync.Pool{
	New: func() interface{} {
		buffer := make([]byte, 1<<20)
		return &buffer
	},
}
func NewReader(ra ReaderAt) io.Reader {
	rd := io.NewSectionReader(ra, 0, ra.Size())
	return rd
}
func ReadBlob(ctx context.Context, provider Provider, desc ocispec.Descriptor) ([]byte, error) {
	ra, err := provider.ReaderAt(ctx, desc)
	if err != nil {
		return nil, err
	}
	defer ra.Close()
	p := make([]byte, ra.Size())
	n, err := ra.ReadAt(p, 0)
	if err == io.EOF {
		if int64(n) != ra.Size() {
			err = io.ErrUnexpectedEOF
		} else {
			err = nil
		}
	}
	return p, err
}
func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, desc ocispec.Descriptor, opts ...Opt) error {
	cw, err := OpenWriter(ctx, cs, WithRef(ref), WithDescriptor(desc))
	if err != nil {
		if !errdefs.IsAlreadyExists(err) {
			return errors.Wrap(err, "failed to open writer")
		}
		return nil  
	}
	defer cw.Close()
	return Copy(ctx, cw, r, desc.Size, desc.Digest, opts...)
}
func OpenWriter(ctx context.Context, cs Ingester, opts ...WriterOpt) (Writer, error) {
	var (
		cw    Writer
		err   error
		retry = 16
	)
	for {
		cw, err = cs.Writer(ctx, opts...)
		if err != nil {
			if !errdefs.IsUnavailable(err) {
				return nil, err
			}
			select {
			case <-time.After(time.Millisecond * time.Duration(rand.Intn(retry))):
				if retry < 2048 {
					retry = retry << 1
				}
				continue
			case <-ctx.Done():
				return nil, err
			}
		}
		break
	}
	return cw, err
}
func Copy(ctx context.Context, cw Writer, r io.Reader, size int64, expected digest.Digest, opts ...Opt) error {
	ws, err := cw.Status()
	if err != nil {
		return errors.Wrap(err, "failed to get status")
	}
	if ws.Offset > 0 {
		r, err = seekReader(r, ws.Offset, size)
		if err != nil {
			return errors.Wrapf(err, "unable to resume write to %v", ws.Ref)
		}
	}
	copied, err := copyWithBuffer(cw, r)
	if err != nil {
		return errors.Wrap(err, "failed to copy")
	}
	if size != 0 && copied < size-ws.Offset {
		return errors.Wrapf(io.ErrUnexpectedEOF, "failed to read expected number of bytes")
	}
	if err := cw.Commit(ctx, size, expected, opts...); err != nil {
		if !errdefs.IsAlreadyExists(err) {
			return errors.Wrapf(err, "failed commit on ref %q", ws.Ref)
		}
	}
	return nil
}
func CopyReaderAt(cw Writer, ra ReaderAt, n int64) error {
	ws, err := cw.Status()
	if err != nil {
		return err
	}
	copied, err := copyWithBuffer(cw, io.NewSectionReader(ra, ws.Offset, n))
	if err != nil {
		return errors.Wrap(err, "failed to copy")
	}
	if copied < n {
		return errors.Wrap(io.ErrUnexpectedEOF, "failed to read expected number of bytes")
	}
	return nil
}
func CopyReader(cw Writer, r io.Reader) (int64, error) {
	ws, err := cw.Status()
	if err != nil {
		return 0, errors.Wrap(err, "failed to get status")
	}
	if ws.Offset > 0 {
		r, err = seekReader(r, ws.Offset, 0)
		if err != nil {
			return 0, errors.Wrapf(err, "unable to resume write to %v", ws.Ref)
		}
	}
	return copyWithBuffer(cw, r)
}