diff options
15 files changed, 321 insertions, 54 deletions
diff --git a/vendor.conf b/vendor.conf index 7c9c96936..dddc225e8 100644 --- a/vendor.conf +++ b/vendor.conf @@ -3,7 +3,7 @@ github.com/sirupsen/logrus v1.0.0 github.com/containers/image b327f751c16e4a189fdcde4ea36be67cc964c605 github.com/docker/docker-credential-helpers d68f9aeca33f5fd3f08eeae5e9d175edf4e731d1 github.com/ostreedev/ostree-go master -github.com/containers/storage 1e5ce40cdb84ab66e26186435b1273e04b879fef +github.com/containers/storage ff8a6d2bf496daf46ab1a153f783a0f6b8762a54 github.com/containernetworking/cni v0.4.0 google.golang.org/grpc v1.0.4 https://github.com/grpc/grpc-go github.com/opencontainers/selinux b29023b86e4a69d1b46b7e7b4e2b6fda03f0b9cd 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. |