Browse Source

Update chroot apply layer to handle decompression outside chroot

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>

Conflicts:
	pkg/archive/diff.go
	pkg/chrootarchive/archive.go

Conflicts:
	pkg/archive/diff.go
	pkg/chrootarchive/diff.go
Michael Crosby 10 years ago
parent
commit
7862f831fe
3 changed files with 60 additions and 31 deletions
  1. 20 19
      pkg/archive/diff.go
  2. 20 5
      pkg/chrootarchive/archive.go
  3. 20 7
      pkg/chrootarchive/diff.go

+ 20 - 19
pkg/archive/diff.go

@@ -15,24 +15,7 @@ import (
 	"github.com/docker/docker/pkg/system"
 )
 
-// ApplyLayer parses a diff in the standard layer format from `layer`, and
-// applies it to the directory `dest`.
-func ApplyLayer(dest string, layer ArchiveReader) error {
-	dest = filepath.Clean(dest)
-
-	// We need to be able to set any perms
-	oldmask, err := system.Umask(0)
-	if err != nil {
-		return err
-	}
-
-	defer system.Umask(oldmask) // ignore err, ErrNotSupportedPlatform
-
-	layer, err = DecompressStream(layer)
-	if err != nil {
-		return err
-	}
-
+func UnpackLayer(dest string, layer ArchiveReader) error {
 	tr := tar.NewReader(layer)
 	trBuf := pools.BufioReader32KPool.Get(tr)
 	defer pools.BufioReader32KPool.Put(trBuf)
@@ -159,6 +142,24 @@ func ApplyLayer(dest string, layer ArchiveReader) error {
 			return err
 		}
 	}
-
 	return nil
 }
+
+// ApplyLayer parses a diff in the standard layer format from `layer`, and
+// applies it to the directory `dest`.
+func ApplyLayer(dest string, layer ArchiveReader) error {
+	dest = filepath.Clean(dest)
+
+	// We need to be able to set any perms
+	oldmask, err := system.Umask(0)
+	if err != nil {
+		return err
+	}
+	defer system.Umask(oldmask) // ignore err, ErrNotSupportedPlatform
+
+	layer, err = DecompressStream(layer)
+	if err != nil {
+		return err
+	}
+	return UnpackLayer(dest, layer)
+}

+ 20 - 5
pkg/chrootarchive/archive.go

@@ -15,6 +15,15 @@ import (
 	"github.com/docker/docker/pkg/reexec"
 )
 
+var chrootArchiver = &archive.Archiver{Untar}
+
+func chroot(path string) error {
+	if err := syscall.Chroot(path); err != nil {
+		return err
+	}
+	return syscall.Chdir("/")
+}
+
 func untar() {
 	runtime.LockOSThread()
 	flag.Parse()
@@ -38,11 +47,17 @@ func untar() {
 	os.Exit(0)
 }
 
-var (
-	chrootArchiver = &archive.Archiver{Untar}
-)
+func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error {
+	if tarArchive == nil {
+		return fmt.Errorf("Empty archive")
+	}
+	if options == nil {
+		options = &archive.TarOptions{}
+	}
+	if options.Excludes == nil {
+		options.Excludes = []string{}
+	}
 
-func Untar(archive io.Reader, dest string, options *archive.TarOptions) error {
 	var buf bytes.Buffer
 	enc := json.NewEncoder(&buf)
 	if err := enc.Encode(options); err != nil {
@@ -55,7 +70,7 @@ func Untar(archive io.Reader, dest string, options *archive.TarOptions) error {
 	}
 
 	cmd := reexec.Command("docker-untar", dest, buf.String())
-	cmd.Stdin = archive
+	cmd.Stdin = tarArchive
 	out, err := cmd.CombinedOutput()
 	if err != nil {
 		return fmt.Errorf("Untar %s %s", err, out)

+ 20 - 7
pkg/chrootarchive/diff.go

@@ -3,8 +3,10 @@ package chrootarchive
 import (
 	"flag"
 	"fmt"
+	"io"
 	"io/ioutil"
 	"os"
+	"path/filepath"
 	"runtime"
 	"syscall"
 
@@ -16,19 +18,20 @@ func applyLayer() {
 	runtime.LockOSThread()
 	flag.Parse()
 
-	if err := syscall.Chroot(flag.Arg(0)); err != nil {
-		fatal(err)
-	}
-	if err := syscall.Chdir("/"); err != nil {
+	if err := chroot(flag.Arg(0)); err != nil {
 		fatal(err)
 	}
+	// We need to be able to set any perms
+	oldmask := syscall.Umask(0)
+	defer syscall.Umask(oldmask)
 	tmpDir, err := ioutil.TempDir("/", "temp-docker-extract")
 	if err != nil {
 		fatal(err)
 	}
 	os.Setenv("TMPDIR", tmpDir)
-	if err := archive.ApplyLayer("/", os.Stdin); err != nil {
-		os.RemoveAll(tmpDir)
+	err = archive.UnpackLayer("/", os.Stdin)
+	os.RemoveAll(tmpDir)
+	if err != nil {
 		fatal(err)
 	}
 	os.RemoveAll(tmpDir)
@@ -37,8 +40,18 @@ func applyLayer() {
 }
 
 func ApplyLayer(dest string, layer archive.ArchiveReader) error {
+	dest = filepath.Clean(dest)
+	decompressed, err := archive.DecompressStream(layer)
+	if err != nil {
+		return err
+	}
+	defer func() {
+		if c, ok := decompressed.(io.Closer); ok {
+			c.Close()
+		}
+	}()
 	cmd := reexec.Command("docker-applyLayer", dest)
-	cmd.Stdin = layer
+	cmd.Stdin = decompressed
 	out, err := cmd.CombinedOutput()
 	if err != nil {
 		return fmt.Errorf("ApplyLayer %s %s", err, out)