Browse Source

Merge pull request #4178 from alexlarsson/fix-aufs-plnk

archive: Handle aufs plink hardlinks in ApplyLayer
Victor Vieux 11 years ago
parent
commit
8f140b2ded
2 changed files with 42 additions and 2 deletions
  1. 1 1
      archive/archive.go
  2. 41 1
      archive/diff.go

+ 1 - 1
archive/archive.go

@@ -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.

+ 41 - 1
archive/diff.go

@@ -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
 			}
 			}