summaryrefslogtreecommitdiff
path: root/vendor
diff options
context:
space:
mode:
Diffstat (limited to 'vendor')
-rw-r--r--vendor/github.com/containers/storage/containers.go23
-rw-r--r--vendor/github.com/containers/storage/containers_ffjson.go2
-rw-r--r--vendor/github.com/containers/storage/drivers/overlay/overlay.go12
-rw-r--r--vendor/github.com/containers/storage/drivers/overlayutils/overlayutils.go6
-rw-r--r--vendor/github.com/containers/storage/images.go23
-rw-r--r--vendor/github.com/containers/storage/images_ffjson.go2
-rw-r--r--vendor/github.com/containers/storage/layers.go27
-rw-r--r--vendor/github.com/containers/storage/layers_ffjson.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/archive.go8
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/archive_linux.go88
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/archive_other.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/changes.go61
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/changes_linux.go82
-rw-r--r--vendor/github.com/containers/storage/store.go35
14 files changed, 320 insertions, 53 deletions
diff --git a/vendor/github.com/containers/storage/containers.go b/vendor/github.com/containers/storage/containers.go
index 5631e31c3..1d8b4d3f6 100644
--- a/vendor/github.com/containers/storage/containers.go
+++ b/vendor/github.com/containers/storage/containers.go
@@ -106,10 +106,25 @@ type containerStore struct {
byname map[string]*Container
}
+func copyContainer(c *Container) *Container {
+ return &Container{
+ ID: c.ID,
+ Names: copyStringSlice(c.Names),
+ ImageID: c.ImageID,
+ LayerID: c.LayerID,
+ Metadata: c.Metadata,
+ BigDataNames: copyStringSlice(c.BigDataNames),
+ BigDataSizes: copyStringInt64Map(c.BigDataSizes),
+ BigDataDigests: copyStringDigestMap(c.BigDataDigests),
+ Created: c.Created,
+ Flags: copyStringInterfaceMap(c.Flags),
+ }
+}
+
func (r *containerStore) Containers() ([]Container, error) {
containers := make([]Container, len(r.containers))
for i := range r.containers {
- containers[i] = *(r.containers[i])
+ containers[i] = *copyContainer(r.containers[i])
}
return containers, nil
}
@@ -277,7 +292,7 @@ func (r *containerStore) Create(id string, names []string, image, layer, metadat
}
err = r.Save()
}
- return container, err
+ return copyContainer(container), err
}
func (r *containerStore) Metadata(id string) (string, error) {
@@ -355,7 +370,7 @@ func (r *containerStore) Delete(id string) error {
func (r *containerStore) Get(id string) (*Container, error) {
if container, ok := r.lookup(id); ok {
- return container, nil
+ return copyContainer(container), nil
}
return nil, ErrContainerUnknown
}
@@ -444,7 +459,7 @@ func (r *containerStore) BigDataNames(id string) ([]string, error) {
if !ok {
return nil, ErrContainerUnknown
}
- return c.BigDataNames, nil
+ return copyStringSlice(c.BigDataNames), nil
}
func (r *containerStore) SetBigData(id, key string, data []byte) error {
diff --git a/vendor/github.com/containers/storage/containers_ffjson.go b/vendor/github.com/containers/storage/containers_ffjson.go
index 952619806..a0fb69eb2 100644
--- a/vendor/github.com/containers/storage/containers_ffjson.go
+++ b/vendor/github.com/containers/storage/containers_ffjson.go
@@ -1,5 +1,5 @@
// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
-// source: containers.go
+// source: ./containers.go
package storage
diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay.go b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
index 4458b679a..de6ee6da5 100644
--- a/vendor/github.com/containers/storage/drivers/overlay/overlay.go
+++ b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
@@ -114,8 +114,8 @@ func init() {
}
// Init returns the a native diff driver for overlay filesystem.
-// If overlay filesystem is not supported on the host, graphdriver.ErrNotSupported is returned as error.
-// If an overlay filesystem is not supported over an existing filesystem then error graphdriver.ErrIncompatibleFS is returned.
+// If overlay filesystem is not supported on the host, a wrapped graphdriver.ErrNotSupported is returned as error.
+// If an overlay filesystem is not supported over an existing filesystem then a wrapped graphdriver.ErrIncompatibleFS is returned.
func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
opts, err := parseOptions(options)
if err != nil {
@@ -151,7 +151,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
if err != nil {
os.Remove(filepath.Join(home, linkDir))
os.Remove(home)
- return nil, errors.Wrap(graphdriver.ErrNotSupported, "kernel does not support overlay fs")
+ return nil, errors.Wrap(err, "kernel does not support overlay fs")
}
if err := mount.MakePrivate(home); err != nil {
@@ -740,6 +740,11 @@ func (d *Driver) Diff(id, parent, mountLabel string) (io.ReadCloser, error) {
return d.naiveDiff.Diff(id, parent, mountLabel)
}
+ lowerDirs, err := d.getLowerDirs(id)
+ if err != nil {
+ return nil, err
+ }
+
diffPath := d.getDiffPath(id)
logrus.Debugf("Tar with options on %s", diffPath)
return archive.TarWithOptions(diffPath, &archive.TarOptions{
@@ -747,6 +752,7 @@ func (d *Driver) Diff(id, parent, mountLabel string) (io.ReadCloser, error) {
UIDMaps: d.uidMaps,
GIDMaps: d.gidMaps,
WhiteoutFormat: archive.OverlayWhiteoutFormat,
+ WhiteoutData: lowerDirs,
})
}
diff --git a/vendor/github.com/containers/storage/drivers/overlayutils/overlayutils.go b/vendor/github.com/containers/storage/drivers/overlayutils/overlayutils.go
index 467733647..49aaad07d 100644
--- a/vendor/github.com/containers/storage/drivers/overlayutils/overlayutils.go
+++ b/vendor/github.com/containers/storage/drivers/overlayutils/overlayutils.go
@@ -3,8 +3,10 @@
package overlayutils
import (
- "errors"
"fmt"
+
+ "github.com/containers/storage/drivers"
+ "github.com/pkg/errors"
)
// ErrDTypeNotSupported denotes that the backing filesystem doesn't support d_type.
@@ -14,5 +16,5 @@ func ErrDTypeNotSupported(driver, backingFs string) error {
msg += " Reformat the filesystem with ftype=1 to enable d_type support."
}
msg += " Running without d_type is not supported."
- return errors.New(msg)
+ return errors.Wrap(graphdriver.ErrNotSupported, msg)
}
diff --git a/vendor/github.com/containers/storage/images.go b/vendor/github.com/containers/storage/images.go
index 962e1bb76..10859e2d8 100644
--- a/vendor/github.com/containers/storage/images.go
+++ b/vendor/github.com/containers/storage/images.go
@@ -124,10 +124,25 @@ type imageStore struct {
bydigest map[digest.Digest][]*Image
}
+func copyImage(i *Image) *Image {
+ return &Image{
+ ID: i.ID,
+ Digest: i.Digest,
+ Names: copyStringSlice(i.Names),
+ TopLayer: i.TopLayer,
+ Metadata: i.Metadata,
+ BigDataNames: copyStringSlice(i.BigDataNames),
+ BigDataSizes: copyStringInt64Map(i.BigDataSizes),
+ BigDataDigests: copyStringDigestMap(i.BigDataDigests),
+ Created: i.Created,
+ Flags: copyStringInterfaceMap(i.Flags),
+ }
+}
+
func (r *imageStore) Images() ([]Image, error) {
images := make([]Image, len(r.images))
for i := range r.images {
- images[i] = *(r.images[i])
+ images[i] = *copyImage(r.images[i])
}
return images, nil
}
@@ -343,7 +358,7 @@ func (r *imageStore) Create(id string, names []string, layer, metadata string, c
}
err = r.Save()
}
- return image, err
+ return copyImage(image), err
}
func (r *imageStore) Metadata(id string) (string, error) {
@@ -450,7 +465,7 @@ func (r *imageStore) Delete(id string) error {
func (r *imageStore) Get(id string) (*Image, error) {
if image, ok := r.lookup(id); ok {
- return image, nil
+ return copyImage(image), nil
}
return nil, ErrImageUnknown
}
@@ -546,7 +561,7 @@ func (r *imageStore) BigDataNames(id string) ([]string, error) {
if !ok {
return nil, ErrImageUnknown
}
- return image.BigDataNames, nil
+ return copyStringSlice(image.BigDataNames), nil
}
func imageSliceWithoutValue(slice []*Image, value *Image) []*Image {
diff --git a/vendor/github.com/containers/storage/images_ffjson.go b/vendor/github.com/containers/storage/images_ffjson.go
index f6a8b0650..f91ee6d4f 100644
--- a/vendor/github.com/containers/storage/images_ffjson.go
+++ b/vendor/github.com/containers/storage/images_ffjson.go
@@ -1,5 +1,5 @@
// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
-// source: images.go
+// source: ./images.go
package storage
diff --git a/vendor/github.com/containers/storage/layers.go b/vendor/github.com/containers/storage/layers.go
index a1be6eee7..91117a4f2 100644
--- a/vendor/github.com/containers/storage/layers.go
+++ b/vendor/github.com/containers/storage/layers.go
@@ -223,10 +223,29 @@ type layerStore struct {
byuncompressedsum map[digest.Digest][]string
}
+func copyLayer(l *Layer) *Layer {
+ return &Layer{
+ ID: l.ID,
+ Names: copyStringSlice(l.Names),
+ Parent: l.Parent,
+ Metadata: l.Metadata,
+ MountLabel: l.MountLabel,
+ MountPoint: l.MountPoint,
+ MountCount: l.MountCount,
+ Created: l.Created,
+ CompressedDigest: l.CompressedDigest,
+ CompressedSize: l.CompressedSize,
+ UncompressedDigest: l.UncompressedDigest,
+ UncompressedSize: l.UncompressedSize,
+ CompressionType: l.CompressionType,
+ Flags: copyStringInterfaceMap(l.Flags),
+ }
+}
+
func (r *layerStore) Layers() ([]Layer, error) {
layers := make([]Layer, len(r.layers))
for i := range r.layers {
- layers[i] = *(r.layers[i])
+ layers[i] = *copyLayer(r.layers[i])
}
return layers, nil
}
@@ -558,7 +577,7 @@ func (r *layerStore) Put(id, parent string, names []string, mountLabel string, o
return nil, -1, err
}
}
- return layer, size, err
+ return copyLayer(layer), size, err
}
func (r *layerStore) CreateWithFlags(id, parent string, names []string, mountLabel string, options map[string]string, writeable bool, flags map[string]interface{}) (layer *Layer, err error) {
@@ -731,7 +750,7 @@ func (r *layerStore) Exists(id string) bool {
func (r *layerStore) Get(id string) (*Layer, error) {
if layer, ok := r.lookup(id); ok {
- return layer, nil
+ return copyLayer(layer), nil
}
return nil, ErrLayerUnknown
}
@@ -1003,7 +1022,7 @@ func (r *layerStore) layersByDigestMap(m map[digest.Digest][]string, d digest.Di
if !ok {
return nil, ErrLayerUnknown
}
- layers = append(layers, *layer)
+ layers = append(layers, *copyLayer(layer))
}
return layers, nil
}
diff --git a/vendor/github.com/containers/storage/layers_ffjson.go b/vendor/github.com/containers/storage/layers_ffjson.go
index 1d494e9d4..608fe1863 100644
--- a/vendor/github.com/containers/storage/layers_ffjson.go
+++ b/vendor/github.com/containers/storage/layers_ffjson.go
@@ -1,5 +1,5 @@
// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
-// source: layers.go. Hack to make this work on github.com
+// source: ./layers.go
package storage
diff --git a/vendor/github.com/containers/storage/pkg/archive/archive.go b/vendor/github.com/containers/storage/pkg/archive/archive.go
index abee36f7e..e74cddd70 100644
--- a/vendor/github.com/containers/storage/pkg/archive/archive.go
+++ b/vendor/github.com/containers/storage/pkg/archive/archive.go
@@ -45,6 +45,10 @@ type (
// This format will be converted to the standard format on pack
// and from the standard format on unpack.
WhiteoutFormat WhiteoutFormat
+ // This is additional data to be used by the converter. It will
+ // not survive a round trip through JSON, so it's primarily
+ // intended for generating archives (i.e., converting writes).
+ WhiteoutData interface{}
// When unpacking, specifies whether overwriting a directory with a
// non-directory is allowed and vice versa.
NoOverwriteDirNonDir bool
@@ -702,7 +706,7 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
compressWriter,
options.ChownOpts,
)
- ta.WhiteoutConverter = getWhiteoutConverter(options.WhiteoutFormat)
+ ta.WhiteoutConverter = getWhiteoutConverter(options.WhiteoutFormat, options.WhiteoutData)
defer func() {
// Make sure to check the error on Close.
@@ -860,7 +864,7 @@ func Unpack(decompressedArchive io.Reader, dest string, options *TarOptions) err
var dirs []*tar.Header
idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
rootIDs := idMappings.RootPair()
- whiteoutConverter := getWhiteoutConverter(options.WhiteoutFormat)
+ whiteoutConverter := getWhiteoutConverter(options.WhiteoutFormat, options.WhiteoutData)
// Iterate through the files in the archive.
loop:
diff --git a/vendor/github.com/containers/storage/pkg/archive/archive_linux.go b/vendor/github.com/containers/storage/pkg/archive/archive_linux.go
index 5a14eb91a..6e33ac38d 100644
--- a/vendor/github.com/containers/storage/pkg/archive/archive_linux.go
+++ b/vendor/github.com/containers/storage/pkg/archive/archive_linux.go
@@ -5,21 +5,27 @@ import (
"os"
"path/filepath"
"strings"
+ "syscall"
"github.com/containers/storage/pkg/system"
"golang.org/x/sys/unix"
)
-func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter {
+func getWhiteoutConverter(format WhiteoutFormat, data interface{}) tarWhiteoutConverter {
if format == OverlayWhiteoutFormat {
- return overlayWhiteoutConverter{}
+ if rolayers, ok := data.([]string); ok && len(rolayers) > 0 {
+ return overlayWhiteoutConverter{rolayers: rolayers}
+ }
+ return overlayWhiteoutConverter{rolayers: nil}
}
return nil
}
-type overlayWhiteoutConverter struct{}
+type overlayWhiteoutConverter struct {
+ rolayers []string
+}
-func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os.FileInfo) (wo *tar.Header, err error) {
+func (o overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os.FileInfo) (wo *tar.Header, err error) {
// convert whiteouts to AUFS format
if fi.Mode()&os.ModeCharDevice != 0 && hdr.Devmajor == 0 && hdr.Devminor == 0 {
// we just rename the file and make it normal
@@ -31,7 +37,7 @@ func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os
}
if fi.Mode()&os.ModeDir != 0 {
- // convert opaque dirs to AUFS format by writing an empty file with the prefix
+ // convert opaque dirs to AUFS format by writing an empty file with the whiteout prefix
opaque, err := system.Lgetxattr(path, "trusted.overlay.opaque")
if err != nil {
return nil, err
@@ -40,20 +46,64 @@ func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os
if hdr.Xattrs != nil {
delete(hdr.Xattrs, "trusted.overlay.opaque")
}
-
- // create a header for the whiteout file
- // it should inherit some properties from the parent, but be a regular file
- wo = &tar.Header{
- Typeflag: tar.TypeReg,
- Mode: hdr.Mode & int64(os.ModePerm),
- Name: filepath.Join(hdr.Name, WhiteoutOpaqueDir),
- Size: 0,
- Uid: hdr.Uid,
- Uname: hdr.Uname,
- Gid: hdr.Gid,
- Gname: hdr.Gname,
- AccessTime: hdr.AccessTime,
- ChangeTime: hdr.ChangeTime,
+ // If there are no lower layers, then it can't have been deleted in this layer.
+ if len(o.rolayers) == 0 {
+ return nil, nil
+ }
+ // At this point, we have a directory that's opaque. If it appears in one of the lower
+ // layers, then it was newly-created here, so it wasn't also deleted here.
+ for _, rolayer := range o.rolayers {
+ stat, statErr := os.Stat(filepath.Join(rolayer, hdr.Name))
+ if statErr != nil && !os.IsNotExist(statErr) && !isENOTDIR(statErr) {
+ // Not sure what happened here.
+ return nil, statErr
+ }
+ if statErr == nil {
+ if stat.Mode()&os.ModeCharDevice != 0 {
+ // It's a whiteout for this directory, so it can't have been
+ // both deleted and recreated in the layer we're diffing.
+ s := stat.Sys().(*syscall.Stat_t)
+ if major(s.Rdev) == 0 && minor(s.Rdev) == 0 {
+ return nil, nil
+ }
+ }
+ // It's not whiteout, so it was there in the older layer, so we need to
+ // add a whiteout for this item in this layer.
+ // create a header for the whiteout file
+ // it should inherit some properties from the parent, but be a regular file
+ wo = &tar.Header{
+ Typeflag: tar.TypeReg,
+ Mode: hdr.Mode & int64(os.ModePerm),
+ Name: filepath.Join(hdr.Name, WhiteoutOpaqueDir),
+ Size: 0,
+ Uid: hdr.Uid,
+ Uname: hdr.Uname,
+ Gid: hdr.Gid,
+ Gname: hdr.Gname,
+ AccessTime: hdr.AccessTime,
+ ChangeTime: hdr.ChangeTime,
+ }
+ break
+ }
+ for dir := filepath.Dir(hdr.Name); dir != "" && dir != "." && dir != string(os.PathSeparator); dir = filepath.Dir(dir) {
+ // Check for whiteout for a parent directory in a parent layer.
+ stat, statErr := os.Stat(filepath.Join(rolayer, dir))
+ if statErr != nil && !os.IsNotExist(statErr) && !isENOTDIR(statErr) {
+ // Not sure what happened here.
+ return nil, statErr
+ }
+ if statErr == nil {
+ if stat.Mode()&os.ModeCharDevice != 0 {
+ // If it's whiteout for a parent directory, then the
+ // original directory wasn't inherited into this layer,
+ // so we don't need to emit whiteout for it.
+ s := stat.Sys().(*syscall.Stat_t)
+ if major(s.Rdev) == 0 && minor(s.Rdev) == 0 {
+ return nil, nil
+ }
+ }
+ }
+ }
}
}
}
diff --git a/vendor/github.com/containers/storage/pkg/archive/archive_other.go b/vendor/github.com/containers/storage/pkg/archive/archive_other.go
index 54acbf285..585faa824 100644
--- a/vendor/github.com/containers/storage/pkg/archive/archive_other.go
+++ b/vendor/github.com/containers/storage/pkg/archive/archive_other.go
@@ -2,6 +2,6 @@
package archive
-func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter {
+func getWhiteoutConverter(format WhiteoutFormat, data interface{}) tarWhiteoutConverter {
return nil
}
diff --git a/vendor/github.com/containers/storage/pkg/archive/changes.go b/vendor/github.com/containers/storage/pkg/archive/changes.go
index 6ba4b8ec6..8ab6b83f5 100644
--- a/vendor/github.com/containers/storage/pkg/archive/changes.go
+++ b/vendor/github.com/containers/storage/pkg/archive/changes.go
@@ -81,7 +81,7 @@ func sameFsTimeSpec(a, b syscall.Timespec) bool {
// Changes walks the path rw and determines changes for the files in the path,
// with respect to the parent layers
func Changes(layers []string, rw string) ([]Change, error) {
- return changes(layers, rw, aufsDeletedFile, aufsMetadataSkip)
+ return changes(layers, rw, aufsDeletedFile, aufsMetadataSkip, aufsWhiteoutPresent)
}
func aufsMetadataSkip(path string) (skip bool, err error) {
@@ -104,10 +104,35 @@ func aufsDeletedFile(root, path string, fi os.FileInfo) (string, error) {
return "", nil
}
+func aufsWhiteoutPresent(root, path string) (bool, error) {
+ f := filepath.Join(filepath.Dir(path), WhiteoutPrefix+filepath.Base(path))
+ _, err := os.Stat(filepath.Join(root, f))
+ if err == nil {
+ return true, nil
+ }
+ if os.IsNotExist(err) || isENOTDIR(err) {
+ return false, nil
+ }
+ return false, err
+}
+
+func isENOTDIR(err error) bool {
+ if err == nil {
+ return false
+ }
+ if perror, ok := err.(*os.PathError); ok {
+ if errno, ok := perror.Err.(syscall.Errno); ok {
+ return errno == syscall.ENOTDIR
+ }
+ }
+ return false
+}
+
type skipChange func(string) (bool, error)
type deleteChange func(string, string, os.FileInfo) (string, error)
+type whiteoutChange func(string, string) (bool, error)
-func changes(layers []string, rw string, dc deleteChange, sc skipChange) ([]Change, error) {
+func changes(layers []string, rw string, dc deleteChange, sc skipChange, wc whiteoutChange) ([]Change, error) {
var (
changes []Change
changedDirs = make(map[string]struct{})
@@ -156,7 +181,28 @@ func changes(layers []string, rw string, dc deleteChange, sc skipChange) ([]Chan
change.Kind = ChangeAdd
// ...Unless it already existed in a top layer, in which case, it's a modification
+ layerScan:
for _, layer := range layers {
+ if wc != nil {
+ // ...Unless a lower layer also had whiteout for this directory or one of its parents,
+ // in which case, it's new
+ ignore, err := wc(layer, path)
+ if err != nil {
+ return err
+ }
+ if ignore {
+ break layerScan
+ }
+ for dir := filepath.Dir(path); dir != "" && dir != string(os.PathSeparator); dir = filepath.Dir(dir) {
+ ignore, err = wc(layer, dir)
+ if err != nil {
+ return err
+ }
+ if ignore {
+ break layerScan
+ }
+ }
+ }
stat, err := os.Stat(filepath.Join(layer, path))
if err != nil && !os.IsNotExist(err) {
return err
@@ -187,10 +233,15 @@ func changes(layers []string, rw string, dc deleteChange, sc skipChange) ([]Chan
}
if change.Kind == ChangeAdd || change.Kind == ChangeDelete {
parent := filepath.Dir(path)
- if _, ok := changedDirs[parent]; !ok && parent != "/" {
- changes = append(changes, Change{Path: parent, Kind: ChangeModify})
- changedDirs[parent] = struct{}{}
+ tail := []Change{}
+ for parent != "/" {
+ if _, ok := changedDirs[parent]; !ok && parent != "/" {
+ tail = append([]Change{{Path: parent, Kind: ChangeModify}}, tail...)
+ changedDirs[parent] = struct{}{}
+ }
+ parent = filepath.Dir(parent)
}
+ changes = append(changes, tail...)
}
// Record change
diff --git a/vendor/github.com/containers/storage/pkg/archive/changes_linux.go b/vendor/github.com/containers/storage/pkg/archive/changes_linux.go
index 90c9a627e..8a82e857d 100644
--- a/vendor/github.com/containers/storage/pkg/archive/changes_linux.go
+++ b/vendor/github.com/containers/storage/pkg/archive/changes_linux.go
@@ -288,26 +288,96 @@ func clen(n []byte) int {
// OverlayChanges walks the path rw and determines changes for the files in the path,
// with respect to the parent layers
func OverlayChanges(layers []string, rw string) ([]Change, error) {
- return changes(layers, rw, overlayDeletedFile, nil)
+ dc := func(root, path string, fi os.FileInfo) (string, error) {
+ return overlayDeletedFile(layers, root, path, fi)
+ }
+ return changes(layers, rw, dc, nil, overlayLowerContainsWhiteout)
}
-func overlayDeletedFile(root, path string, fi os.FileInfo) (string, error) {
+func overlayLowerContainsWhiteout(root, path string) (bool, error) {
+ // Whiteout for a file or directory has the same name, but is for a character
+ // device with major/minor of 0/0.
+ stat, err := os.Stat(filepath.Join(root, path))
+ if err != nil && !os.IsNotExist(err) && !isENOTDIR(err) {
+ // Not sure what happened here.
+ return false, err
+ }
+ if err == nil && stat.Mode()&os.ModeCharDevice != 0 {
+ // Check if there's whiteout for the specified item in the specified layer.
+ s := stat.Sys().(*syscall.Stat_t)
+ if major(s.Rdev) == 0 && minor(s.Rdev) == 0 {
+ return true, nil
+ }
+ }
+ return false, nil
+}
+
+func overlayDeletedFile(layers []string, root, path string, fi os.FileInfo) (string, error) {
+ // If it's a whiteout item, then a file or directory with that name is removed by this layer.
if fi.Mode()&os.ModeCharDevice != 0 {
s := fi.Sys().(*syscall.Stat_t)
if major(s.Rdev) == 0 && minor(s.Rdev) == 0 {
return path, nil
}
}
- if fi.Mode()&os.ModeDir != 0 {
- opaque, err := system.Lgetxattr(filepath.Join(root, path), "trusted.overlay.opaque")
- if err != nil {
+ // After this we only need to pay attention to directories.
+ if !fi.IsDir() {
+ return "", nil
+ }
+ // If the directory isn't marked as opaque, then it's just a normal directory.
+ opaque, err := system.Lgetxattr(filepath.Join(root, path), "trusted.overlay.opaque")
+ if err != nil {
+ return "", err
+ }
+ if len(opaque) != 1 || opaque[0] != 'y' {
+ return "", err
+ }
+ // If there are no lower layers, then it can't have been deleted and recreated in this layer.
+ if len(layers) == 0 {
+ return "", err
+ }
+ // At this point, we have a directory that's opaque. If it appears in one of the lower
+ // layers, then it was newly-created here, so it wasn't also deleted here.
+ for _, layer := range layers {
+ stat, err := os.Stat(filepath.Join(layer, path))
+ if err != nil && !os.IsNotExist(err) && !isENOTDIR(err) {
+ // Not sure what happened here.
return "", err
}
- if len(opaque) == 1 && opaque[0] == 'y' {
+ if err == nil {
+ if stat.Mode()&os.ModeCharDevice != 0 {
+ // It's a whiteout for this directory, so it can't have been
+ // deleted in this layer.
+ s := stat.Sys().(*syscall.Stat_t)
+ if major(s.Rdev) == 0 && minor(s.Rdev) == 0 {
+ return "", nil
+ }
+ }
+ // It's not whiteout, so it was there in the older layer, so it has to be
+ // marked as deleted in this layer.
return path, nil
}
+ for dir := filepath.Dir(path); dir != "" && dir != string(os.PathSeparator); dir = filepath.Dir(dir) {
+ // Check for whiteout for a parent directory.
+ stat, err := os.Stat(filepath.Join(layer, dir))
+ if err != nil && !os.IsNotExist(err) && !isENOTDIR(err) {
+ // Not sure what happened here.
+ return "", err
+ }
+ if err == nil {
+ if stat.Mode()&os.ModeCharDevice != 0 {
+ // If it's whiteout for a parent directory, then the
+ // original directory wasn't inherited into the top layer.
+ s := stat.Sys().(*syscall.Stat_t)
+ if major(s.Rdev) == 0 && minor(s.Rdev) == 0 {
+ return "", nil
+ }
+ }
+ }
+ }
}
+ // We didn't find the same path in any older layers, so it was new in this one.
return "", nil
}
diff --git a/vendor/github.com/containers/storage/store.go b/vendor/github.com/containers/storage/store.go
index a31a08b2a..c7de67ec5 100644
--- a/vendor/github.com/containers/storage/store.go
+++ b/vendor/github.com/containers/storage/store.go
@@ -2350,6 +2350,41 @@ func stringSliceWithoutValue(slice []string, value string) []string {
return modified
}
+func copyStringSlice(slice []string) []string {
+ if len(slice) == 0 {
+ return nil
+ }
+ ret := make([]string, len(slice))
+ copy(ret, slice)
+ return ret
+}
+
+func copyStringInt64Map(m map[string]int64) map[string]int64 {
+ ret := make(map[string]int64, len(m))
+ for k, v := range m {
+ ret[k] = v
+ }
+ return ret
+}
+
+func copyStringDigestMap(m map[string]digest.Digest) map[string]digest.Digest {
+ ret := make(map[string]digest.Digest, len(m))
+ for k, v := range m {
+ ret[k] = v
+ }
+ return ret
+}
+
+// copyStringInterfaceMap still forces us to assume that the interface{} is
+// a non-pointer scalar value
+func copyStringInterfaceMap(m map[string]interface{}) map[string]interface{} {
+ ret := make(map[string]interface{}, len(m))
+ for k, v := range m {
+ ret[k] = v
+ }
+ return ret
+}
+
const configFile = "/etc/containers/storage.conf"
// OptionsConfig represents the "storage.options" TOML config table.