vendor: update c/{common,storage}

Closes: https://github.com/containers/podman/issues/25572

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
Giuseppe Scrivano
2025-03-26 11:24:16 +01:00
parent b58250b35d
commit 7f592742b8
27 changed files with 759 additions and 277 deletions

View File

@ -25,7 +25,7 @@ func (i *Image) History(ctx context.Context) ([]ImageHistory, error) {
return nil, err
}
layerTree, err := i.runtime.newFreshLayerTree()
layerTree, err := i.runtime.newFreshLayerTree(ctx)
if err != nil {
return nil, err
}

View File

@ -191,13 +191,21 @@ func (i *Image) IsReadOnly() bool {
}
// IsDangling returns true if the image is dangling, that is an untagged image
// without children.
// without children and not used in a manifest list.
func (i *Image) IsDangling(ctx context.Context) (bool, error) {
return i.isDangling(ctx, nil)
images, layers, err := i.runtime.getImagesAndLayers()
if err != nil {
return false, err
}
tree, err := i.runtime.newLayerTreeFromData(ctx, images, layers, true)
if err != nil {
return false, err
}
return i.isDangling(ctx, tree)
}
// isDangling returns true if the image is dangling, that is an untagged image
// without children. If tree is nil, it will created for this invocation only.
// without children and not used in a manifest list. If tree is nil, it will created for this invocation only.
func (i *Image) isDangling(ctx context.Context, tree *layerTree) (bool, error) {
if len(i.Names()) > 0 {
return false, nil
@ -206,7 +214,8 @@ func (i *Image) isDangling(ctx context.Context, tree *layerTree) (bool, error) {
if err != nil {
return false, err
}
return len(children) == 0, nil
_, usedInManfiestList := tree.manifestListDigests[i.Digest()]
return (len(children) == 0 && !usedInManfiestList), nil
}
// IsIntermediate returns true if the image is an intermediate image, that is
@ -258,7 +267,7 @@ func (i *Image) TopLayer() string {
// Parent returns the parent image or nil if there is none
func (i *Image) Parent(ctx context.Context) (*Image, error) {
tree, err := i.runtime.newFreshLayerTree()
tree, err := i.runtime.newFreshLayerTree(ctx)
if err != nil {
return nil, err
}
@ -292,7 +301,7 @@ func (i *Image) Children(ctx context.Context) ([]*Image, error) {
// created for this invocation only.
func (i *Image) getChildren(ctx context.Context, all bool, tree *layerTree) ([]*Image, error) {
if tree == nil {
t, err := i.runtime.newFreshLayerTree()
t, err := i.runtime.newFreshLayerTree(ctx)
if err != nil {
return nil, err
}
@ -789,27 +798,25 @@ func (i *Image) Mount(_ context.Context, mountOptions []string, mountLabel strin
// Mountpoint returns the path to image's mount point. The path is empty if
// the image is not mounted.
func (i *Image) Mountpoint() (string, error) {
mountedTimes, err := i.runtime.store.Mounted(i.TopLayer())
if err != nil || mountedTimes == 0 {
if errors.Is(err, storage.ErrLayerUnknown) {
// Can happen, Podman did it, but there's no
// explanation why.
err = nil
for _, layerID := range append([]string{i.TopLayer()}, i.storageImage.MappedTopLayers...) {
mountedTimes, err := i.runtime.store.Mounted(layerID)
if err != nil {
if errors.Is(err, storage.ErrLayerUnknown) {
// Can happen, Podman did it, but there's no
// explanation why.
continue
}
return "", err
}
if mountedTimes > 0 {
layer, err := i.runtime.store.Layer(layerID)
if err != nil {
return "", err
}
return filepath.EvalSymlinks(layer.MountPoint)
}
return "", err
}
layer, err := i.runtime.store.Layer(i.TopLayer())
if err != nil {
return "", err
}
mountPoint, err := filepath.EvalSymlinks(layer.MountPoint)
if err != nil {
return "", err
}
return mountPoint, nil
return "", nil
}
// Unmount the image. Use force to ignore the reference counter and forcefully

View File

@ -3,6 +3,7 @@
package libimage
import (
"context"
"fmt"
"strings"
@ -13,7 +14,7 @@ import (
// Tree generates a tree for the specified image and its layers. Use
// `traverseChildren` to traverse the layers of all children. By default, only
// layers of the image are printed.
func (i *Image) Tree(traverseChildren bool) (string, error) {
func (i *Image) Tree(ctx context.Context, traverseChildren bool) (string, error) {
// NOTE: a string builder prevents us from copying to much data around
// and compile the string when and where needed.
sb := &strings.Builder{}
@ -37,7 +38,7 @@ func (i *Image) Tree(traverseChildren bool) (string, error) {
fmt.Fprintf(sb, "No Image Layers")
}
layerTree, err := i.runtime.newFreshLayerTree()
layerTree, err := i.runtime.newFreshLayerTree(ctx)
if err != nil {
return "", err
}

View File

@ -8,6 +8,7 @@ import (
"github.com/containers/storage"
storageTypes "github.com/containers/storage/types"
digest "github.com/opencontainers/go-digest"
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/sirupsen/logrus"
)
@ -22,6 +23,10 @@ type layerTree struct {
// emptyImages do not have any top-layer so we cannot create a
// *layerNode for them.
emptyImages []*Image
// manifestList keep track of images based on their digest.
// Library will use this map when checking if a image is dangling.
// If an image is used in a manifestList it is NOT dangling
manifestListDigests map[digest.Digest]struct{}
}
// node returns a layerNode for the specified layerID.
@ -90,20 +95,21 @@ func (l *layerNode) repoTags() ([]string, error) {
}
// newFreshLayerTree extracts a layerTree from consistent layers and images in the local storage.
func (r *Runtime) newFreshLayerTree() (*layerTree, error) {
func (r *Runtime) newFreshLayerTree(ctx context.Context) (*layerTree, error) {
images, layers, err := r.getImagesAndLayers()
if err != nil {
return nil, err
}
return r.newLayerTreeFromData(images, layers)
return r.newLayerTreeFromData(ctx, images, layers, false)
}
// newLayerTreeFromData extracts a layerTree from the given the layers and images.
// The caller is responsible for (layers, images) being consistent.
func (r *Runtime) newLayerTreeFromData(images []*Image, layers []storage.Layer) (*layerTree, error) {
func (r *Runtime) newLayerTreeFromData(ctx context.Context, images []*Image, layers []storage.Layer, generateManifestDigestList bool) (*layerTree, error) {
tree := layerTree{
nodes: make(map[string]*layerNode),
ociCache: make(map[string]*ociv1.Image),
nodes: make(map[string]*layerNode),
ociCache: make(map[string]*ociv1.Image),
manifestListDigests: make(map[digest.Digest]struct{}),
}
// First build a tree purely based on layer information.
@ -124,6 +130,21 @@ func (r *Runtime) newLayerTreeFromData(images []*Image, layers []storage.Layer)
topLayer := img.TopLayer()
if topLayer == "" {
tree.emptyImages = append(tree.emptyImages, img)
// When img is a manifest list, cache the lists of
// digests refereenced in manifest list. Digests can
// be used to check for dangling images.
if !generateManifestDigestList {
continue
}
if manifestList, _ := img.IsManifestList(ctx); manifestList {
mlist, err := img.ToManifestList()
if err != nil {
return nil, err
}
for _, digest := range mlist.list.Instances() {
tree.manifestListDigests[digest] = struct{}{}
}
}
continue
}
node, exists := tree.nodes[topLayer]

View File

@ -634,7 +634,7 @@ func (r *Runtime) ListImages(ctx context.Context, options *ListImagesOptions) ([
var tree *layerTree
if needsLayerTree {
tree, err = r.newLayerTreeFromData(images, snapshot.Layers)
tree, err = r.newLayerTreeFromData(ctx, images, snapshot.Layers, true)
if err != nil {
return nil, err
}