diff --git a/oci/layer/generate.go b/oci/layer/generate.go index a231d2ea..ffd56247 100644 --- a/oci/layer/generate.go +++ b/oci/layer/generate.go @@ -88,7 +88,7 @@ func GenerateLayer(path string, deltas []mtree.InodeDelta, opt *RepackOptions) ( return errors.Wrapf(err, "couldn't determine overlay whiteout for %s", fullPath) } - whiteout, err := isOverlayWhiteout(fi) + whiteout, err := isOverlayWhiteout(fi, fullPath, tg.fsEval) if err != nil { return err } @@ -166,7 +166,7 @@ func GenerateInsertLayer(root string, target string, opaque bool, opt *RepackOpt } pathInTar := path.Join(target, curPath[len(root):]) - whiteout, err := isOverlayWhiteout(info) + whiteout, err := isOverlayWhiteout(info, curPath, tg.fsEval) if err != nil { return err } diff --git a/oci/layer/tar_extract_linux_test.go b/oci/layer/tar_extract_linux_test.go index 7ab74662..9aa1267e 100644 --- a/oci/layer/tar_extract_linux_test.go +++ b/oci/layer/tar_extract_linux_test.go @@ -96,7 +96,7 @@ func TestUnpackEntryOverlayFSWhiteout(t *testing.T) { t.Fatalf("failed to stat `file`: %v", err) } - whiteout, err := isOverlayWhiteout(fi) + whiteout, err := isOverlayWhiteout(fi, filepath.Join(dir, "file"), te.fsEval) if err != nil { t.Fatalf("failed to check overlay whiteout: %v", err) } diff --git a/oci/layer/utils.go b/oci/layer/utils.go index f22122f7..8d8e1574 100644 --- a/oci/layer/utils.go +++ b/oci/layer/utils.go @@ -25,6 +25,7 @@ import ( "github.com/apex/log" rspec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/umoci/pkg/fseval" "github.com/opencontainers/umoci/pkg/idtools" "github.com/pkg/errors" rootlesscontainers "github.com/rootless-containers/proto/go-proto" @@ -230,7 +231,7 @@ func InnerErrno(err error) error { // isOverlayWhiteout returns true if the FileInfo represents an overlayfs style // whiteout (i.e. mknod c 0 0) and false otherwise. -func isOverlayWhiteout(info os.FileInfo) (bool, error) { +func isOverlayWhiteout(info os.FileInfo, fullPath string, fsEval fseval.FsEval) (bool, error) { var major, minor uint32 switch stat := info.Sys().(type) { case *unix.Stat_t: @@ -243,6 +244,25 @@ func isOverlayWhiteout(info os.FileInfo) (bool, error) { return false, errors.Errorf("[internal error] unknown stat info type %T", info.Sys()) } - return major == 0 && minor == 0 && - info.Mode()&os.ModeCharDevice != 0, nil + if major == 0 && minor == 0 && + info.Mode()&os.ModeCharDevice != 0 { + return true, nil + } + + // also evaluate xattrs which may have opaque value set + attr, err := fsEval.Lgetxattr(fullPath, "user.overlay.opaque") + if err != nil { + v := errors.Cause(err) + if !errors.Is(err, os.ErrNotExist) && v != unix.EOPNOTSUPP && v != unix.ENODATA && v != unix.EPERM && v != unix.EACCES { + return false, errors.Errorf("[internal error] unknown stat info type %T", info.Sys()) + } + + return false, nil + } + + if string(attr) == "y" { + return true, nil + } + + return false, nil }