diff --git a/core/content/helpers.go b/core/content/helpers.go index 7bbed58a05..3a79876160 100644 --- a/core/content/helpers.go +++ b/core/content/helpers.go @@ -188,14 +188,20 @@ func OpenWriter(ctx context.Context, cs Ingester, opts ...WriterOpt) (Writer, er // Copy copies data with the expected digest from the reader into the // provided content store writer. This copy commits the writer. // -// This is useful when the digest and size are known beforehand. When -// the size or digest is unknown, these values may be empty. +// A size of 0 indicates an unknown size, in which case the reader is +// copied until EOF. For backward compatibility, -1 is also accepted +// as an unknown size. Other negative sizes are invalid. Positive sizes +// are enforced, and an empty expected digest disables digest verification. // // Copy is buffered, so no need to wrap reader in buffered io. func Copy(ctx context.Context, cw Writer, or io.Reader, size int64, expected digest.Digest, opts ...Opt) error { - if size < 0 { + if size < -1 { return fmt.Errorf("invalid content size %d: %w", size, errdefs.ErrInvalidArgument) } + if size == -1 { + // Writer.Commit uses 0 for an unknown size. + size = 0 + } for i := 0; ; i++ { if i >= 1 { log.G(ctx).WithField("digest", expected).Debugf("retrying copy due to reset") diff --git a/core/content/helpers_test.go b/core/content/helpers_test.go index ace6a2818a..893981bc81 100644 --- a/core/content/helpers_test.go +++ b/core/content/helpers_test.go @@ -205,10 +205,34 @@ func TestCopy(t *testing.T) { expectedErr: errdefs.ErrFailedPrecondition, }, { - name: "copy fails when size is negative", + name: "copy with unspecified size (zero)", + source: copySource{ + reader: strings.NewReader("content"), + size: 0, + digest: digest.FromString("content"), + }, + writer: fakeWriter{ + Buffer: &bytes.Buffer{}, + }, + expected: "content", + }, + { + name: "copy with unspecified size (-1)", source: copySource{ reader: strings.NewReader("content"), size: -1, + digest: digest.FromString("content"), + }, + writer: fakeWriter{ + Buffer: &bytes.Buffer{}, + }, + expected: "content", + }, + { + name: "copy with invalid negative size", + source: copySource{ + reader: strings.NewReader("content"), + size: -2, }, writer: fakeWriter{ Buffer: &bytes.Buffer{}, @@ -230,7 +254,9 @@ func TestCopy(t *testing.T) { assert.ErrorIs(t, err, testcase.expectedErr) return } - + if testcase.source.size == -1 { + assert.Zero(t, testcase.writer.committedSize) + } assert.NoError(t, err) assert.Equal(t, testcase.source.digest, testcase.writer.committedDigest) assert.Equal(t, testcase.expected, testcase.writer.String()) @@ -273,6 +299,7 @@ type commitFunction func() error type fakeWriter struct { *bytes.Buffer + committedSize int64 committedDigest digest.Digest status Status commitFunc commitFunction @@ -284,6 +311,7 @@ func (f *fakeWriter) Close() error { } func (f *fakeWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...Opt) error { + f.committedSize = size f.committedDigest = expected if f.commitFunc == nil { return nil