Skip to content

Commit

Permalink
Reverse the order of extraction of layers
Browse files Browse the repository at this point in the history
Signed-off-by: Joao Pereira <[email protected]>
  • Loading branch information
joaopapereira committed Jan 30, 2024
1 parent 671367f commit 5452eb3
Showing 1 changed file with 38 additions and 9 deletions.
47 changes: 38 additions & 9 deletions pkg/imgpkg/image/dir_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,19 @@ func (i *DirImage) AsDirectory() error {
return err
}

for idx, imgLayer := range layers {
fileMap := map[string]bool{}

// we iterate through the layers in reverse order because it makes handling
// whiteout layers more efficient, since we can just keep track of the removed
// files as we see .wh. layers and ignore those in previous layers.
for idx := len(layers) - 1; idx >= 0; idx-- {
imgLayer := layers[idx]
digest, err := imgLayer.Digest()
if err != nil {
return err
}

i.logger.Logf("Extracting layer '%s' (%d/%d)\n", digest, idx+1, len(layers))
i.logger.Logf("Extracting layer '%s' (%d/%d)\n", digest, len(layers)-idx, len(layers))

layerStream, err := imgLayer.Uncompressed()
if err != nil {
Expand All @@ -65,7 +71,7 @@ func (i *DirImage) AsDirectory() error {

defer layerStream.Close()

err = i.writeLayer(layerStream)
err = i.writeLayer(fileMap, layerStream)
if err != nil {
return err
}
Expand All @@ -76,7 +82,7 @@ func (i *DirImage) AsDirectory() error {

// Taken from https://github.com/concourse/registry-image-resource/blob/b5481130ad61bc74e0a74f9b00b287b3a24bab88/cmd/in/unpack.go

func (i *DirImage) writeLayer(stream io.Reader) error {
func (i *DirImage) writeLayer(fileMap map[string]bool, stream io.Reader) error {
tarReader := tar.NewReader(stream)

for {
Expand All @@ -102,6 +108,12 @@ func (i *DirImage) writeLayer(stream io.Reader) error {
if err != nil {
return nil
}
fileMap[base] = true
continue
}

// check for a whited out parent directory
if inWhiteoutDir(fileMap, path) {
continue
}

Expand All @@ -116,6 +128,7 @@ func (i *DirImage) writeLayer(stream io.Reader) error {
}
}

fileMap[hdr.Name] = true
err = i.extractTarEntry(hdr, tarReader)
if err != nil {
return err
Expand All @@ -125,6 +138,23 @@ func (i *DirImage) writeLayer(stream io.Reader) error {
return nil
}

func inWhiteoutDir(fileMap map[string]bool, file string) bool {
for {
if file == "" {
break
}
dirname := filepath.Dir(file)
if file == dirname {
break
}
if val, ok := fileMap[dirname]; ok && val {
return true
}
file = dirname
}
return false
}

// Taken from https://github.com/concourse/go-archive/blob/f26802964d15194bddb07bf116ea567c56af973f/tarfs/extract.go

func (i *DirImage) extractTarEntry(header *tar.Header, input io.Reader) error {
Expand All @@ -150,10 +180,7 @@ func (i *DirImage) extractTarEntry(header *tar.Header, input io.Reader) error {

switch header.Typeflag {
case tar.TypeDir:
err := os.MkdirAll(path, permMode)
if err != nil {
return err
}
return nil

case tar.TypeReg, tar.TypeRegA:
file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, permMode)
Expand All @@ -175,7 +202,9 @@ func (i *DirImage) extractTarEntry(header *tar.Header, input io.Reader) error {
case tar.TypeLink, tar.TypeSymlink:
// skipping symlinks as a security feature
return nil

case tar.TypeChar, tar.TypeBlock:
// skipping devices
return nil
default:
return fmt.Errorf("Unsupported tar entry type '%c' for file '%s'", header.Typeflag, header.Name)
}
Expand Down

0 comments on commit 5452eb3

Please sign in to comment.