package containerd import ( "context" "fmt" "github.com/containerd/containerd/v2/core/mount" "github.com/containerd/log" "github.com/moby/go-archive" "github.com/moby/moby/v2/daemon/container" "github.com/moby/moby/v2/daemon/internal/stringid" ) func (i *ImageService) Changes(ctx context.Context, ctr *container.Container) ([]archive.Change, error) { rwl := ctr.RWLayer if rwl == nil { return nil, fmt.Errorf("RWLayer is unexpectedly nil for container %s", ctr.ID) } snapshotter := i.client.SnapshotService(ctr.Driver) info, err := snapshotter.Stat(ctx, ctr.ID) if err != nil { return nil, err } id := stringid.GenerateRandomID() parentViewKey := ctr.ID + "-parent-view-" + id imageMounts, _ := snapshotter.View(ctx, parentViewKey, info.Parent) defer func() { if err := snapshotter.Remove(ctx, parentViewKey); err != nil { log.G(ctx).WithError(err).Warn("error removing the parent view snapshot") } }() containerRoot, err := rwl.Mount(ctr.GetMountLabel()) if err != nil { return nil, err } defer func() { if err := rwl.Unmount(); err != nil { log.G(ctx).WithFields(log.Fields{"error": err, "container": ctr.ID}).Warn("Failed to unmount container RWLayer after export") } }() var changes []archive.Change err = mount.WithReadonlyTempMount(ctx, imageMounts, func(imageRoot string) error { changes, err = archive.ChangesDirs(containerRoot, imageRoot) return err }) return changes, err }