github.com/opencontainers/umoci@v0.4.8-0.20240508124516-656e4836fb0d/oci/casext/blob.go (about)

     1  /*
     2   * umoci: Umoci Modifies Open Containers' Images
     3   * Copyright (C) 2016-2020 SUSE LLC
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *    http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package casext
    19  
    20  import (
    21  	"context"
    22  	"io"
    23  	"io/ioutil"
    24  
    25  	ispec "github.com/opencontainers/image-spec/specs-go/v1"
    26  	"github.com/opencontainers/umoci/oci/casext/mediatype"
    27  	"github.com/opencontainers/umoci/pkg/system"
    28  	"github.com/pkg/errors"
    29  )
    30  
    31  // Blob represents a "parsed" blob in an OCI image's blob store. MediaType
    32  // offers a type-safe way of checking what the type of Data is.
    33  type Blob struct {
    34  	// Descriptor is the {mediatype,digest,length} 3-tuple. Note that this
    35  	// isn't updated if the Data is modified.
    36  	Descriptor ispec.Descriptor
    37  
    38  	// Data is the "parsed" blob taken from the OCI image's blob store, and is
    39  	// typed according to the media type. The default mappings from MIME =>
    40  	// type is as follows (more can be registered using RegisterParser).
    41  	//
    42  	// ispec.MediaTypeDescriptor => ispec.Descriptor
    43  	// ispec.MediaTypeImageManifest => ispec.Manifest
    44  	// ispec.MediaTypeImageIndex => ispec.Index
    45  	// ispec.MediaTypeImageLayer => io.ReadCloser
    46  	// ispec.MediaTypeImageLayerGzip => io.ReadCloser
    47  	// ispec.MediaTypeImageLayerNonDistributable => io.ReadCloser
    48  	// ispec.MediaTypeImageLayerNonDistributableGzip => io.ReadCloser
    49  	// ispec.MediaTypeImageConfig => ispec.Image
    50  	// unknown => io.ReadCloser
    51  	Data interface{}
    52  }
    53  
    54  // Close cleans up all of the resources for the opened blob.
    55  func (b *Blob) Close() error {
    56  	if closer, ok := b.Data.(io.Closer); ok {
    57  		return closer.Close()
    58  	}
    59  	return nil
    60  }
    61  
    62  // FromDescriptor parses the blob referenced by the given descriptor.
    63  func (e Engine) FromDescriptor(ctx context.Context, descriptor ispec.Descriptor) (_ *Blob, Err error) {
    64  	reader, err := e.GetVerifiedBlob(ctx, descriptor)
    65  	if err != nil {
    66  		return nil, errors.Wrap(err, "get blob")
    67  	}
    68  
    69  	blob := Blob{
    70  		Descriptor: descriptor,
    71  		Data:       reader,
    72  	}
    73  
    74  	if fn := mediatype.GetParser(descriptor.MediaType); fn != nil {
    75  		defer func() {
    76  			if _, err := system.Copy(ioutil.Discard, reader); Err == nil {
    77  				Err = errors.Wrapf(err, "discard trailing %q blob", descriptor.MediaType)
    78  			}
    79  			if err := reader.Close(); Err == nil {
    80  				Err = errors.Wrapf(err, "close %q blob", descriptor.MediaType)
    81  			}
    82  		}()
    83  
    84  		data, err := fn(reader)
    85  		if err != nil {
    86  			return nil, errors.Wrapf(err, "parse %s", descriptor.MediaType)
    87  		}
    88  		blob.Data = data
    89  	}
    90  	if blob.Data == nil {
    91  		return nil, errors.Errorf("[internal error] b.Data was nil after parsing")
    92  	}
    93  	return &blob, nil
    94  }