diff --git a/content/helpers.go b/content/helpers.go index 859de7095..3610c844f 100644 --- a/content/helpers.go +++ b/content/helpers.go @@ -41,6 +41,17 @@ func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, size i } defer cw.Close() + return Copy(cw, r, size, expected) +} + +// Copy copies data with the expected digest from the reader into the +// provided content store writer. +// +// This is useful when the digest and size are known beforehand. When +// the size or digest is unknown, these values may be empty. +// +// Copy is buffered, so no need to wrap reader in buffered io. +func Copy(cw Writer, r io.Reader, size int64, expected digest.Digest) error { ws, err := cw.Status() if err != nil { return err @@ -50,7 +61,7 @@ func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, size i r, err = seekReader(r, ws.Offset, size) if err != nil { if !isUnseekable(err) { - return errors.Wrapf(err, "unabled to resume write to %v", ref) + return errors.Wrapf(err, "unabled to resume write to %v", ws.Ref) } // reader is unseekable, try to move the writer back to the start. @@ -69,7 +80,7 @@ func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, size i if err := cw.Commit(size, expected); err != nil { if !IsExists(err) { - return errors.Wrapf(err, "failed commit on ref %q", ref) + return errors.Wrapf(err, "failed commit on ref %q", ws.Ref) } } diff --git a/remotes/handlers.go b/remotes/handlers.go index ec9551172..b4818863a 100644 --- a/remotes/handlers.go +++ b/remotes/handlers.go @@ -56,11 +56,22 @@ func FetchHandler(ingester content.Ingester, fetcher Fetcher) images.HandlerFunc func fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc ocispec.Descriptor) error { log.G(ctx).Debug("fetch") ref := MakeRefKey(ctx, desc) + + cw, err := ingester.Writer(ctx, ref, desc.Size, desc.Digest) + if err != nil { + if !content.IsExists(err) { + return err + } + + return nil + } + defer cw.Close() + rc, err := fetcher.Fetch(ctx, desc) if err != nil { return err } defer rc.Close() - return content.WriteBlob(ctx, ingester, ref, rc, desc.Size, desc.Digest) + return content.Copy(cw, rc, desc.Size, desc.Digest) }