Skip to content

Commit

Permalink
[Whiteout] Simple refactoring of whiteout file handling.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 712416206
  • Loading branch information
Mario Leyva authored and copybara-github committed Feb 7, 2025
1 parent 620a293 commit 07bf513
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 7 deletions.
12 changes: 6 additions & 6 deletions artifact/image/layerscanning/image/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,10 +325,10 @@ func fillChainLayerWithFilesFromTar(img *Image, tarReader *tar.Reader, originLay
continue
}

tombstone := strings.HasPrefix(basename, whiteout.WhiteoutPrefix)
isWhiteout := whiteout.IsWhiteout(basename)
// TODO: b/379094217 - Handle Opaque Whiteouts
if tombstone {
basename = basename[len(whiteout.WhiteoutPrefix):]
if isWhiteout {
basename = whiteout.ToPath(basename)
}

// If we're checking a directory, don't filepath.Join names.
Expand All @@ -346,11 +346,11 @@ func fillChainLayerWithFilesFromTar(img *Image, tarReader *tar.Reader, originLay
var newNode *fileNode
switch header.Typeflag {
case tar.TypeDir:
newNode, err = img.handleDir(realFilePath, virtualPath, originLayerID, tarReader, header, tombstone)
newNode, err = img.handleDir(realFilePath, virtualPath, originLayerID, tarReader, header, isWhiteout)
case tar.TypeReg:
newNode, err = img.handleFile(realFilePath, virtualPath, originLayerID, tarReader, header, tombstone)
newNode, err = img.handleFile(realFilePath, virtualPath, originLayerID, tarReader, header, isWhiteout)
case tar.TypeSymlink, tar.TypeLink:
newNode, err = img.handleSymlink(realFilePath, virtualPath, originLayerID, tarReader, header, tombstone)
newNode, err = img.handleSymlink(realFilePath, virtualPath, originLayerID, tarReader, header, isWhiteout)
default:
log.Warnf("unsupported file type: %v, path: %s", header.Typeflag, header.Name)
continue
Expand Down
32 changes: 31 additions & 1 deletion artifact/image/whiteout/whiteout.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package whiteout
import (
"fmt"
"io/fs"
"path"
"path/filepath"
"strings"

Expand All @@ -39,7 +40,7 @@ func Files(scalibrfs scalibrfs.FS) (map[string]struct{}, error) {

err := fs.WalkDir(scalibrfs, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
//nolint:nilerr // continue walking if there is an error
//nolint:nilerr // Continue walking if there is an error.
return nil
}

Expand All @@ -60,3 +61,32 @@ func Files(scalibrfs scalibrfs.FS) (map[string]struct{}, error) {
}
return whiteouts, nil
}

// IsWhiteout returns true if a path is a whiteout path.
func IsWhiteout(p string) bool {
_, file := path.Split(p)
return strings.HasPrefix(file, WhiteoutPrefix)
}

// ToWhiteout returns the whiteout version of a path.
func ToWhiteout(p string) string {
dir, file := path.Split(p)
return filepath.Join(dir, fmt.Sprintf("%s%s", WhiteoutPrefix, file))
}

// ToPath returns the non whiteout version of a path.
func ToPath(p string) string {
dir, file := path.Split(p)

if strings.HasPrefix(file, WhiteoutPrefix) {
file = strings.TrimPrefix(file, WhiteoutPrefix)
}

nonWhitoutPath := filepath.Join(dir, file)

if dir != "" && file == "" {
nonWhitoutPath = fmt.Sprintf("%s/", nonWhitoutPath)
}

return nonWhitoutPath
}
116 changes: 116 additions & 0 deletions artifact/image/whiteout/whiteout_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,119 @@ func TestWhiteout(t *testing.T) {
})
}
}

func TestIsWhiteout(t *testing.T) {
testCases := []struct {
desc string
path string
want bool
}{
{
desc: "Empty path",
path: "",
want: false,
},
{
desc: "Simple file path",
path: "file.txt",
want: false,
},
{
desc: "Path with directories",
path: "dir1/dir2/foo.txt",
want: false,
},
{
desc: "Simple whiteout path",
path: ".wh.file.txt",
want: true,
},
{
desc: "Whiteout path with directories",
path: "dir1/dir2/.wh.foo.txt",
want: true,
},
}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
got := whiteout.IsWhiteout(tc.path)
if got != tc.want {
t.Errorf("IsWhiteout(%q) = %v, want: %v", tc.path, got, tc.want)
}
})
}
}

func TestToWhiteout(t *testing.T) {
testCases := []struct {
desc string
path string
want string
}{
{
desc: "Empty path",
path: "",
want: ".wh.",
},
{
desc: "Simple file path",
path: "file.txt",
want: ".wh.file.txt",
},
{
desc: "Path with directories",
path: "dir1/dir2/foo.txt",
want: "dir1/dir2/.wh.foo.txt",
},
}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
got := whiteout.ToWhiteout(tc.path)
if got != tc.want {
t.Errorf("ToWhiteout(%q) = %q, want: %q", tc.path, got, tc.want)
}
})
}
}

func TestToPath(t *testing.T) {
testCases := []struct {
desc string
path string
want string
}{
{
desc: "Empty path",
path: "",
want: "",
},
{
desc: "Simple file path",
path: "file.txt",
want: "file.txt",
},
{
desc: "Path with directories",
path: "dir1/dir2/foo.txt",
want: "dir1/dir2/foo.txt",
},
{
desc: "Simple whiteout path",
path: ".wh.file.txt",
want: "file.txt",
},
{
desc: "Whiteout path with directories",
path: "dir1/dir2/.wh.foo.txt",
want: "dir1/dir2/foo.txt",
},
}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
got := whiteout.ToPath(tc.path)
if got != tc.want {
t.Errorf("ToPath(%q) = %q, want: %q", tc.path, got, tc.want)
}
})
}
}

0 comments on commit 07bf513

Please sign in to comment.