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 }