LayerInfosForCopy() returns the list of layer blobs that make up the root filesystem of the image, after they've been decompressed.
(ctx context.Context, instanceDigest *digest.Digest)
| 282 | // LayerInfosForCopy() returns the list of layer blobs that make up the root filesystem of |
| 283 | // the image, after they've been decompressed. |
| 284 | func (s *storageImageSource) LayerInfosForCopy(ctx context.Context, instanceDigest *digest.Digest) ([]types.BlobInfo, error) { |
| 285 | manifestBlob, manifestType, err := s.GetManifest(ctx, instanceDigest) |
| 286 | if err != nil { |
| 287 | return nil, fmt.Errorf("reading image manifest for %q: %w", s.image.ID, err) |
| 288 | } |
| 289 | if manifest.MIMETypeIsMultiImage(manifestType) { |
| 290 | return nil, errors.New("can't copy layers for a manifest list (shouldn't be attempted)") |
| 291 | } |
| 292 | man, err := manifest.FromBlob(manifestBlob, manifestType) |
| 293 | if err != nil { |
| 294 | return nil, fmt.Errorf("parsing image manifest for %q: %w", s.image.ID, err) |
| 295 | } |
| 296 | |
| 297 | uncompressedLayerType := "" |
| 298 | switch manifestType { |
| 299 | case imgspecv1.MediaTypeImageManifest: |
| 300 | uncompressedLayerType = imgspecv1.MediaTypeImageLayer |
| 301 | case manifest.DockerV2Schema1MediaType, manifest.DockerV2Schema1SignedMediaType, manifest.DockerV2Schema2MediaType: |
| 302 | uncompressedLayerType = manifest.DockerV2SchemaLayerMediaTypeUncompressed |
| 303 | } |
| 304 | |
| 305 | physicalBlobInfos := []types.BlobInfo{} // Built reversed |
| 306 | layerID := s.image.TopLayer |
| 307 | for layerID != "" { |
| 308 | layer, err := s.imageRef.transport.store.Layer(layerID) |
| 309 | if err != nil { |
| 310 | return nil, fmt.Errorf("reading layer %q in image %q: %w", layerID, s.image.ID, err) |
| 311 | } |
| 312 | |
| 313 | blobDigest := layer.UncompressedDigest |
| 314 | if blobDigest == "" { |
| 315 | if layer.TOCDigest == "" { |
| 316 | return nil, fmt.Errorf("uncompressed digest and TOC digest for layer %q is unknown", layerID) |
| 317 | } |
| 318 | if layer.Flags == nil || layer.Flags[expectedLayerDiffIDFlag] == nil { |
| 319 | return nil, fmt.Errorf("TOC digest %q for layer %q is present but %q flag is not set", layer.TOCDigest, layerID, expectedLayerDiffIDFlag) |
| 320 | } |
| 321 | expectedDigest, ok := layer.Flags[expectedLayerDiffIDFlag].(string) |
| 322 | if !ok { |
| 323 | return nil, fmt.Errorf("TOC digest %q for layer %q is present but %q flag is not a string", layer.TOCDigest, layerID, expectedLayerDiffIDFlag) |
| 324 | } |
| 325 | // If the layer is stored by its TOC, report the expected diffID as the layer Digest; |
| 326 | // the generic code is responsible for validating the digest. |
| 327 | // We can locate the layer without further c/storage help using s.getBlobMutexProtected.digestToLayerID. |
| 328 | blobDigest, err = digest.Parse(expectedDigest) |
| 329 | if err != nil { |
| 330 | return nil, fmt.Errorf("parsing expected diffID %q for layer %q: %w", expectedDigest, layerID, err) |
| 331 | } |
| 332 | } |
| 333 | size := layer.UncompressedSize |
| 334 | if size < 0 { |
| 335 | size = -1 |
| 336 | } |
| 337 | s.getBlobMutex.Lock() |
| 338 | s.getBlobMutexProtected.digestToLayerID[blobDigest] = layer.ID |
| 339 | s.getBlobMutex.Unlock() |
| 340 | blobInfo := types.BlobInfo{ |
| 341 | Digest: blobDigest, |
nothing calls this directly
no test coverage detected