mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
archive: Handle aufs plink hardlinks in ApplyLayer
Files in the .wh..wh.plnk directory are ignored, but other files inside the tarfile can be hardlinks to these files. This is not something that normally happens, as on aufs unmount such files are supposed to be dropped via the "auplink" too, yet images on the index (such as shipyard/shipyard, e.g. layer f73c835af6d58b6fc827b400569f79a8f28e54f5bb732be063e1aacefbc374d0) contains such files. We handle these by extracting these files to a temporary directory and resolve such hardlinks via the temporary files. This fixes https://github.com/dotcloud/docker/issues/3884 Docker-DCO-1.1-Signed-off-by: Alexander Larsson <alexl@redhat.com> (github: alexlarsson)
This commit is contained in:
parent
581ee7e584
commit
6889cd9f9c
2 changed files with 42 additions and 2 deletions
|
@ -186,7 +186,7 @@ func addTarFile(path, name string, tw *tar.Writer) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTarFile(path, extractDir string, hdr *tar.Header, reader *tar.Reader) error {
|
func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader) error {
|
||||||
switch hdr.Typeflag {
|
switch hdr.Typeflag {
|
||||||
case tar.TypeDir:
|
case tar.TypeDir:
|
||||||
// Create directory unless it exists as a directory already.
|
// Create directory unless it exists as a directory already.
|
||||||
|
|
|
@ -2,7 +2,9 @@ package archive
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.google.com/p/go/src/pkg/archive/tar"
|
"code.google.com/p/go/src/pkg/archive/tar"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -42,6 +44,9 @@ func ApplyLayer(dest string, layer ArchiveReader) error {
|
||||||
|
|
||||||
var dirs []*tar.Header
|
var dirs []*tar.Header
|
||||||
|
|
||||||
|
aufsTempdir := ""
|
||||||
|
aufsHardlinks := make(map[string]*tar.Header)
|
||||||
|
|
||||||
// Iterate through the files in the archive.
|
// Iterate through the files in the archive.
|
||||||
for {
|
for {
|
||||||
hdr, err := tr.Next()
|
hdr, err := tr.Next()
|
||||||
|
@ -72,6 +77,22 @@ func ApplyLayer(dest string, layer ArchiveReader) error {
|
||||||
|
|
||||||
// Skip AUFS metadata dirs
|
// Skip AUFS metadata dirs
|
||||||
if strings.HasPrefix(hdr.Name, ".wh..wh.") {
|
if strings.HasPrefix(hdr.Name, ".wh..wh.") {
|
||||||
|
// Regular files inside /.wh..wh.plnk can be used as hardlink targets
|
||||||
|
// We don't want this directory, but we need the files in them so that
|
||||||
|
// such hardlinks can be resolved.
|
||||||
|
if strings.HasPrefix(hdr.Name, ".wh..wh.plnk") && hdr.Typeflag == tar.TypeReg {
|
||||||
|
basename := filepath.Base(hdr.Name)
|
||||||
|
aufsHardlinks[basename] = hdr
|
||||||
|
if aufsTempdir == "" {
|
||||||
|
if aufsTempdir, err = ioutil.TempDir("", "dockerplnk"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(aufsTempdir)
|
||||||
|
}
|
||||||
|
if err := createTarFile(filepath.Join(aufsTempdir, basename), dest, hdr, tr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +117,26 @@ func ApplyLayer(dest string, layer ArchiveReader) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := createTarFile(path, dest, hdr, tr); err != nil {
|
srcData := io.Reader(tr)
|
||||||
|
srcHdr := hdr
|
||||||
|
|
||||||
|
// Hard links into /.wh..wh.plnk don't work, as we don't extract that directory, so
|
||||||
|
// we manually retarget these into the temporary files we extracted them into
|
||||||
|
if hdr.Typeflag == tar.TypeLink && strings.HasPrefix(filepath.Clean(hdr.Linkname), ".wh..wh.plnk") {
|
||||||
|
linkBasename := filepath.Base(hdr.Linkname)
|
||||||
|
srcHdr = aufsHardlinks[linkBasename]
|
||||||
|
if srcHdr == nil {
|
||||||
|
return fmt.Errorf("Invalid aufs hardlink")
|
||||||
|
}
|
||||||
|
tmpFile, err := os.Open(filepath.Join(aufsTempdir, linkBasename))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer tmpFile.Close()
|
||||||
|
srcData = tmpFile
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := createTarFile(path, dest, srcHdr, srcData); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue