Skip to content

Commit

Permalink
fix: handle overlay xattr opaque bit
Browse files Browse the repository at this point in the history
Current behavior determines if a path is a whiteout if a overlay char
dev is present.

Additionally, also check the extended attrs.

For files, this is not important: if a file /foo/bar exists in
some two layers, then the higher layer's version will replace
the lower layer's version whether or not the opaque bit is set.

However, directories behave differently.  If /foo exists in two
layers and no opaque bit is set, then we see the union of their
contents.  But if the opaque bit is set on the higher layer's
version, then we should not see the lower layer's version.

So, in that case, create a whiteout /.wh_foo.

Signed-off-by: Ramkumar Chinchani <[email protected]>
  • Loading branch information
rchincha committed Apr 1, 2024
1 parent 0a7d3ec commit 3db0591
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 6 deletions.
4 changes: 2 additions & 2 deletions oci/layer/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion oci/layer/tar_extract_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
26 changes: 23 additions & 3 deletions oci/layer/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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:
Expand All @@ -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
}

0 comments on commit 3db0591

Please sign in to comment.