11package containerimage
22
33import (
4- "bytes"
54 "context"
65 "encoding/json"
76 "fmt"
7+ "io"
88 "reflect"
99 "strconv"
1010 "strings"
@@ -342,7 +342,7 @@ func (ic *ImageWriter) Commit(ctx context.Context, inp *exporter.Source, session
342342 }
343343 idxDone := progress .OneOff (ctx , "exporting manifest list " + idxDigest .String ())
344344
345- if err := content .WriteBlob (ctx , ic .opt .ContentStore , idxDigest .String (), bytes . NewReader (idxBytes ), idxDesc , content .WithLabels (labels )); err != nil {
345+ if err := content .WriteBlob (ctx , ic .opt .ContentStore , idxDigest .String (), newBytesReader (idxBytes ), idxDesc , content .WithLabels (labels )); err != nil {
346346 return nil , idxDone (errors .Wrapf (err , "error writing manifest list blob %s" , idxDigest ))
347347 }
348348 idxDone (nil )
@@ -530,7 +530,7 @@ func (ic *ImageWriter) commitDistributionManifest(ctx context.Context, opts *Ima
530530 }
531531 mfstDone := progress .OneOff (ctx , "exporting manifest " + mfstDigest .String ())
532532
533- if err := content .WriteBlob (ctx , ic .opt .ContentStore , mfstDigest .String (), bytes . NewReader (mfstJSON ), mfstDesc , content .WithLabels ((labels ))); err != nil {
533+ if err := content .WriteBlob (ctx , ic .opt .ContentStore , mfstDigest .String (), newBytesReader (mfstJSON ), mfstDesc , content .WithLabels ((labels ))); err != nil {
534534 return nil , nil , mfstDone (errors .Wrapf (err , "error writing manifest blob %s" , mfstDigest ))
535535 }
536536 mfstDone (nil )
@@ -542,7 +542,7 @@ func (ic *ImageWriter) commitDistributionManifest(ctx context.Context, opts *Ima
542542 }
543543 configDone := progress .OneOff (ctx , "exporting config " + configDigest .String ())
544544
545- if err := content .WriteBlob (ctx , ic .opt .ContentStore , configDigest .String (), bytes . NewReader (config ), configDesc ); err != nil {
545+ if err := content .WriteBlob (ctx , ic .opt .ContentStore , configDigest .String (), newBytesReader (config ), configDesc ); err != nil {
546546 return nil , nil , configDone (errors .Wrap (err , "error writing config blob" ))
547547 }
548548 configDone (nil )
@@ -584,7 +584,7 @@ func (ic *ImageWriter) commitAttestationsManifest(ctx context.Context, opts *Ima
584584 },
585585 }
586586
587- if err := content .WriteBlob (ctx , ic .opt .ContentStore , digest .String (), bytes . NewReader (data ), desc ); err != nil {
587+ if err := content .WriteBlob (ctx , ic .opt .ContentStore , digest .String (), newBytesReader (data ), desc ); err != nil {
588588 return nil , errors .Wrapf (err , "error writing data blob %s" , digest )
589589 }
590590 layers [i ] = desc
@@ -641,10 +641,10 @@ func (ic *ImageWriter) commitAttestationsManifest(ctx context.Context, opts *Ima
641641 }
642642
643643 done := progress .OneOff (ctx , "exporting attestation manifest " + mfstDigest .String ())
644- if err := content .WriteBlob (ctx , ic .opt .ContentStore , mfstDigest .String (), bytes . NewReader (mfstJSON ), mfstDesc , content .WithLabels ((labels ))); err != nil {
644+ if err := content .WriteBlob (ctx , ic .opt .ContentStore , mfstDigest .String (), newBytesReader (mfstJSON ), mfstDesc , content .WithLabels ((labels ))); err != nil {
645645 return nil , done (errors .Wrapf (err , "error writing manifest blob %s" , mfstDigest ))
646646 }
647- if err := content .WriteBlob (ctx , ic .opt .ContentStore , configDesc .Digest .String (), bytes . NewReader (config ), configDesc ); err != nil {
647+ if err := content .WriteBlob (ctx , ic .opt .ContentStore , configDesc .Digest .String (), newBytesReader (config ), configDesc ); err != nil {
648648 return nil , done (errors .Wrap (err , "error writing config blob" ))
649649 }
650650 done (nil )
@@ -947,3 +947,41 @@ func getRefMetadata(ref cache.ImmutableRef, limit int) []refMetadata {
947947 }
948948 return metas
949949}
950+
951+ // bytesReader is an alternative version of the bytes.Reader that implements
952+ // io.WriterTo by sending chunks instead of the entire buffer at once.
953+ //
954+ // This is needed to workaround https://github.com/containerd/containerd/issues/11440.
955+ // When that is fixed, this can be removed.
956+ type bytesReader struct {
957+ p []byte
958+ }
959+
960+ func newBytesReader (p []byte ) * bytesReader {
961+ return & bytesReader {p }
962+ }
963+
964+ func (r * bytesReader ) Read (p []byte ) (n int , err error ) {
965+ if len (r .p ) == 0 {
966+ return 0 , io .EOF
967+ }
968+ n = copy (p , r .p )
969+ r .p = r .p [n :]
970+ return n , nil
971+ }
972+
973+ func (r * bytesReader ) WriteTo (w io.Writer ) (n int64 , err error ) {
974+ const maxBufferSize = 8 << 20
975+ for len (r .p ) > 0 && err == nil {
976+ sz := len (r .p )
977+ if sz > maxBufferSize {
978+ sz = maxBufferSize
979+ }
980+
981+ var n0 int
982+ n0 , err = w .Write (r .p [:sz ])
983+ n += int64 (n0 )
984+ r .p = r .p [n0 :]
985+ }
986+ return n , err
987+ }
0 commit comments