package contentutil import ( "context" "io" "github.com/containerd/containerd/content" "github.com/containerd/containerd/remotes" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" ) func FromFetcher(f remotes.Fetcher) content.Provider { return &fetchedProvider{ f: f, } } type fetchedProvider struct { f remotes.Fetcher } func (p *fetchedProvider) ReaderAt(ctx context.Context, desc ocispecs.Descriptor) (content.ReaderAt, error) { rc, err := p.f.Fetch(ctx, desc) if err != nil { return nil, err } return &readerAt{Reader: rc, Closer: rc, size: desc.Size}, nil } type readerAt struct { io.Reader io.Closer size int64 offset int64 } func (r *readerAt) ReadAt(b []byte, off int64) (int, error) { if ra, ok := r.Reader.(io.ReaderAt); ok { return ra.ReadAt(b, off) } if r.offset != off { if seeker, ok := r.Reader.(io.Seeker); ok { if _, err := seeker.Seek(off, io.SeekStart); err != nil { return 0, err } r.offset = off } else { return 0, errors.Errorf("unsupported offset") } } var totalN int for len(b) > 0 { n, err := r.Reader.Read(b) if err == io.EOF && n == len(b) { err = nil } r.offset += int64(n) totalN += n b = b[n:] if err != nil { return totalN, err } } return totalN, nil } func (r *readerAt) Size() int64 { return r.size }