1
0
mirror of https://github.com/containers/image.git synced 2025-04-18 19:44:05 +03:00

Merge pull request #2807 from mtrmac/tarball-compression-5.34

[5.34] Correctly compute DiffID, and try to set the correct MIME type, for non-gzip input to `tarball:`
This commit is contained in:
Paul Holzinger 2025-03-27 14:22:56 +01:00 committed by GitHub
commit 6b6fd183b8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -14,8 +14,9 @@ import (
"github.com/containers/image/v5/internal/imagesource/impl"
"github.com/containers/image/v5/internal/imagesource/stubs"
"github.com/containers/image/v5/pkg/compression"
compressionTypes "github.com/containers/image/v5/pkg/compression/types"
"github.com/containers/image/v5/types"
"github.com/klauspost/pgzip"
digest "github.com/opencontainers/go-digest"
imgspecs "github.com/opencontainers/image-spec/specs-go"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
@ -82,31 +83,47 @@ func (r *tarballReference) NewImageSource(ctx context.Context, sys *types.System
}
}
// Default to assuming the layer is compressed.
layerType := imgspecv1.MediaTypeImageLayerGzip
// Set up to digest the file as it is.
blobIDdigester := digest.Canonical.Digester()
reader = io.TeeReader(reader, blobIDdigester.Hash())
// Set up to digest the file after we maybe decompress it.
diffIDdigester := digest.Canonical.Digester()
uncompressed, err := pgzip.NewReader(reader)
if err == nil {
// It is compressed, so the diffID is the digest of the uncompressed version
reader = io.TeeReader(uncompressed, diffIDdigester.Hash())
} else {
// It is not compressed, so the diffID and the blobID are going to be the same
diffIDdigester = blobIDdigester
layerType = imgspecv1.MediaTypeImageLayer
uncompressed = nil
}
// TODO: This can take quite some time, and should ideally be cancellable using ctx.Done().
if _, err := io.Copy(io.Discard, reader); err != nil {
return nil, fmt.Errorf("error reading %q: %w", filename, err)
}
if uncompressed != nil {
uncompressed.Close()
var layerType string
var diffIDdigester digest.Digester
// If necessary, digest the file after we decompress it.
if err := func() error { // A scope for defer
format, decompressor, reader, err := compression.DetectCompressionFormat(reader)
if err != nil {
return err
}
if decompressor != nil {
uncompressed, err := decompressor(reader)
if err != nil {
return err
}
defer uncompressed.Close()
// It is compressed, so the diffID is the digest of the uncompressed version
diffIDdigester = digest.Canonical.Digester()
reader = io.TeeReader(uncompressed, diffIDdigester.Hash())
switch format.Name() {
case compressionTypes.GzipAlgorithmName:
layerType = imgspecv1.MediaTypeImageLayerGzip
case compressionTypes.ZstdAlgorithmName:
layerType = imgspecv1.MediaTypeImageLayerZstd
default: // This is incorrect, but we have no good options, and it is what this transport was historically doing.
layerType = imgspecv1.MediaTypeImageLayerGzip
}
} else {
// It is not compressed, so the diffID and the blobID are going to be the same
diffIDdigester = blobIDdigester
layerType = imgspecv1.MediaTypeImageLayer
}
// TODO: This can take quite some time, and should ideally be cancellable using ctx.Done().
if _, err := io.Copy(io.Discard, reader); err != nil {
return fmt.Errorf("error reading %q: %w", filename, err)
}
return nil
}(); err != nil {
return nil, err
}
// Grab our uncompressed and possibly-compressed digests and sizes.