From d025345cddedd2539502df9ca17c18e74285ca28 Mon Sep 17 00:00:00 2001 From: John Howard Date: Thu, 14 May 2015 15:08:00 -0700 Subject: [PATCH] Windows: chrootarchive refactor Signed-off-by: John Howard --- chrootarchive/archive.go | 26 +++++++++++++++--------- chrootarchive/archive_test.go | 30 +++++++++++++-------------- chrootarchive/archive_unix.go | 14 +++++++++++++ chrootarchive/archive_windows.go | 6 ++++++ chrootarchive/diff.go | 35 ++++++++++++++++++++++++-------- 5 files changed, 77 insertions(+), 34 deletions(-) create mode 100644 chrootarchive/archive_unix.go create mode 100644 chrootarchive/archive_windows.go diff --git a/chrootarchive/archive.go b/chrootarchive/archive.go index 49d1917..a94330a 100644 --- a/chrootarchive/archive.go +++ b/chrootarchive/archive.go @@ -9,21 +9,14 @@ import ( "os" "path/filepath" "runtime" - "syscall" "github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/reexec" + "github.com/docker/docker/pkg/system" ) var chrootArchiver = &archive.Archiver{Untar: 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,7 +31,20 @@ func untar() { if err := chroot(flag.Arg(0)); err != nil { fatal(err) } - if err := archive.Unpack(os.Stdin, "/", options); err != nil { + + // Explanation of Windows difference. Windows does not support chroot. + // untar() is a helper function for the command line in the format + // "docker docker-untar directory input". In Windows, directory will be + // something like \docker-buildnnnnnnnnn. So, just use that directory + // directly instead. + // + // One example of where this is used is in the docker build command where the + // dockerfile will be unpacked to the machine on which the daemon runs. + rootPath := "/" + if runtime.GOOS == "windows" { + rootPath = flag.Arg(0) + } + if err := archive.Unpack(os.Stdin, rootPath, options); err != nil { fatal(err) } // fully consume stdin in case it is zero padded @@ -59,7 +65,7 @@ func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error dest = filepath.Clean(dest) if _, err := os.Stat(dest); os.IsNotExist(err) { - if err := os.MkdirAll(dest, 0777); err != nil { + if err := system.MkdirAll(dest, 0777); err != nil { return err } } diff --git a/chrootarchive/archive_test.go b/chrootarchive/archive_test.go index f9b5b09..1d6c2b9 100644 --- a/chrootarchive/archive_test.go +++ b/chrootarchive/archive_test.go @@ -7,7 +7,6 @@ import ( "io" "io/ioutil" "os" - "path" "path/filepath" "strings" "testing" @@ -15,6 +14,7 @@ import ( "github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/reexec" + "github.com/docker/docker/pkg/system" ) func init() { @@ -28,7 +28,7 @@ func TestChrootTarUntar(t *testing.T) { } defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "src") - if err := os.MkdirAll(src, 0700); err != nil { + if err := system.MkdirAll(src, 0700); err != nil { t.Fatal(err) } if err := ioutil.WriteFile(filepath.Join(src, "toto"), []byte("hello toto"), 0644); err != nil { @@ -42,7 +42,7 @@ func TestChrootTarUntar(t *testing.T) { t.Fatal(err) } dest := filepath.Join(tmpdir, "src") - if err := os.MkdirAll(dest, 0700); err != nil { + if err := system.MkdirAll(dest, 0700); err != nil { t.Fatal(err) } if err := Untar(stream, dest, &archive.TarOptions{ExcludePatterns: []string{"lolo"}}); err != nil { @@ -59,7 +59,7 @@ func TestChrootUntarWithHugeExcludesList(t *testing.T) { } defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "src") - if err := os.MkdirAll(src, 0700); err != nil { + if err := system.MkdirAll(src, 0700); err != nil { t.Fatal(err) } if err := ioutil.WriteFile(filepath.Join(src, "toto"), []byte("hello toto"), 0644); err != nil { @@ -70,7 +70,7 @@ func TestChrootUntarWithHugeExcludesList(t *testing.T) { t.Fatal(err) } dest := filepath.Join(tmpdir, "dest") - if err := os.MkdirAll(dest, 0700); err != nil { + if err := system.MkdirAll(dest, 0700); err != nil { t.Fatal(err) } options := &archive.TarOptions{} @@ -101,11 +101,11 @@ func prepareSourceDirectory(numberOfFiles int, targetPath string, makeSymLinks b fileData := []byte("fooo") for n := 0; n < numberOfFiles; n++ { fileName := fmt.Sprintf("file-%d", n) - if err := ioutil.WriteFile(path.Join(targetPath, fileName), fileData, 0700); err != nil { + if err := ioutil.WriteFile(filepath.Join(targetPath, fileName), fileData, 0700); err != nil { return 0, err } if makeSymLinks { - if err := os.Symlink(path.Join(targetPath, fileName), path.Join(targetPath, fileName+"-link")); err != nil { + if err := os.Symlink(filepath.Join(targetPath, fileName), filepath.Join(targetPath, fileName+"-link")); err != nil { return 0, err } } @@ -157,7 +157,7 @@ func TestChrootTarUntarWithSymlink(t *testing.T) { } defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "src") - if err := os.MkdirAll(src, 0700); err != nil { + if err := system.MkdirAll(src, 0700); err != nil { t.Fatal(err) } if _, err := prepareSourceDirectory(10, src, true); err != nil { @@ -179,7 +179,7 @@ func TestChrootCopyWithTar(t *testing.T) { } defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "src") - if err := os.MkdirAll(src, 0700); err != nil { + if err := system.MkdirAll(src, 0700); err != nil { t.Fatal(err) } if _, err := prepareSourceDirectory(10, src, true); err != nil { @@ -225,7 +225,7 @@ func TestChrootCopyFileWithTar(t *testing.T) { } defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "src") - if err := os.MkdirAll(src, 0700); err != nil { + if err := system.MkdirAll(src, 0700); err != nil { t.Fatal(err) } if _, err := prepareSourceDirectory(10, src, true); err != nil { @@ -268,7 +268,7 @@ func TestChrootUntarPath(t *testing.T) { } defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "src") - if err := os.MkdirAll(src, 0700); err != nil { + if err := system.MkdirAll(src, 0700); err != nil { t.Fatal(err) } if _, err := prepareSourceDirectory(10, src, true); err != nil { @@ -329,7 +329,7 @@ func TestChrootUntarEmptyArchiveFromSlowReader(t *testing.T) { } defer os.RemoveAll(tmpdir) dest := filepath.Join(tmpdir, "dest") - if err := os.MkdirAll(dest, 0700); err != nil { + if err := system.MkdirAll(dest, 0700); err != nil { t.Fatal(err) } stream := &slowEmptyTarReader{size: 10240, chunkSize: 1024} @@ -345,7 +345,7 @@ func TestChrootApplyEmptyArchiveFromSlowReader(t *testing.T) { } defer os.RemoveAll(tmpdir) dest := filepath.Join(tmpdir, "dest") - if err := os.MkdirAll(dest, 0700); err != nil { + if err := system.MkdirAll(dest, 0700); err != nil { t.Fatal(err) } stream := &slowEmptyTarReader{size: 10240, chunkSize: 1024} @@ -361,7 +361,7 @@ func TestChrootApplyDotDotFile(t *testing.T) { } defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "src") - if err := os.MkdirAll(src, 0700); err != nil { + if err := system.MkdirAll(src, 0700); err != nil { t.Fatal(err) } if err := ioutil.WriteFile(filepath.Join(src, "..gitme"), []byte(""), 0644); err != nil { @@ -372,7 +372,7 @@ func TestChrootApplyDotDotFile(t *testing.T) { t.Fatal(err) } dest := filepath.Join(tmpdir, "dest") - if err := os.MkdirAll(dest, 0700); err != nil { + if err := system.MkdirAll(dest, 0700); err != nil { t.Fatal(err) } if _, err := ApplyLayer(dest, stream); err != nil { diff --git a/chrootarchive/archive_unix.go b/chrootarchive/archive_unix.go new file mode 100644 index 0000000..62c46f0 --- /dev/null +++ b/chrootarchive/archive_unix.go @@ -0,0 +1,14 @@ +// +build !windows + +package chrootarchive + +import ( + "syscall" +) + +func chroot(path string) error { + if err := syscall.Chroot(path); err != nil { + return err + } + return syscall.Chdir("/") +} diff --git a/chrootarchive/archive_windows.go b/chrootarchive/archive_windows.go new file mode 100644 index 0000000..dccfb87 --- /dev/null +++ b/chrootarchive/archive_windows.go @@ -0,0 +1,6 @@ +package chrootarchive + +// chroot is not supported by Windows +func chroot(path string) error { + return nil +} diff --git a/chrootarchive/diff.go b/chrootarchive/diff.go index 8d97c76..334679d 100644 --- a/chrootarchive/diff.go +++ b/chrootarchive/diff.go @@ -9,10 +9,10 @@ import ( "os" "path/filepath" "runtime" - "syscall" "github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/reexec" + "github.com/docker/docker/pkg/system" ) type applyLayerResponse struct { @@ -20,23 +20,40 @@ type applyLayerResponse struct { } func applyLayer() { + + var ( + root = "/" + tmpDir = "" + err error + ) + runtime.LockOSThread() flag.Parse() - if err := chroot(flag.Arg(0)); err != nil { - fatal(err) + if runtime.GOOS != "windows" { + if err := chroot(flag.Arg(0)); err != nil { + fatal(err) + } + + // We need to be able to set any perms + oldmask, err := system.Umask(0) + defer system.Umask(oldmask) + if err != nil { + fatal(err) + } + } else { + // As Windows does not support chroot or umask, we use the directory + // passed in which will be \docker-buildnnnnnnnn instead of + // the 'chroot-root', "/" + root = flag.Arg(0) } - // 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 { + if tmpDir, err = ioutil.TempDir(root, "temp-docker-extract"); err != nil { fatal(err) } os.Setenv("TMPDIR", tmpDir) - size, err := archive.UnpackLayer("/", os.Stdin) + size, err := archive.UnpackLayer(root, os.Stdin) os.RemoveAll(tmpDir) if err != nil { fatal(err)