diff --git a/daemon/daemonbuilder/builder.go b/daemon/daemonbuilder/builder.go index fec37a6a84..e286508604 100644 --- a/daemon/daemonbuilder/builder.go +++ b/daemon/daemonbuilder/builder.go @@ -101,6 +101,7 @@ func (d Docker) ContainerAttach(cID string, stdin io.ReadCloser, stdout, stderr func (d Docker) BuilderCopy(cID string, destPath string, src builder.FileInfo, decompress bool) error { srcPath := src.Path() destExists := true + destDir := false rootUID, rootGID := d.Daemon.GetRemappedUIDGID() // Work in daemon-local OS specific file paths @@ -124,6 +125,7 @@ func (d Docker) BuilderCopy(cID string, destPath string, src builder.FileInfo, d // Preserve the trailing slash // TODO: why are we appending another path separator if there was already one? if strings.HasSuffix(destPath, string(os.PathSeparator)) || destPath == "." { + destDir = true dest += string(os.PathSeparator) } @@ -166,7 +168,7 @@ func (d Docker) BuilderCopy(cID string, destPath string, src builder.FileInfo, d } // only needed for fixPermissions, but might as well put it before CopyFileWithTar - if destExists && destStat.IsDir() { + if destDir || (destExists && destStat.IsDir()) { destPath = filepath.Join(destPath, src.Name()) } diff --git a/integration-cli/docker_cli_build_test.go b/integration-cli/docker_cli_build_test.go index b8972844d2..ba977194f9 100644 --- a/integration-cli/docker_cli_build_test.go +++ b/integration-cli/docker_cli_build_test.go @@ -3240,6 +3240,46 @@ func (s *DockerSuite) TestBuildAddFileNotFound(c *check.C) { } } +func (s *DockerSuite) TestBuildAddChangeOwnership(c *check.C) { + testRequires(c, DaemonIsLinux) + name := "testbuildaddown" + + ctx := func() *FakeContext { + dockerfile := ` + FROM busybox + ADD foo /bar/ + RUN [ $(stat -c %U:%G "/bar") = 'root:root' ] + RUN [ $(stat -c %U:%G "/bar/foo") = 'root:root' ] + ` + tmpDir, err := ioutil.TempDir("", "fake-context") + c.Assert(err, check.IsNil) + testFile, err := os.Create(filepath.Join(tmpDir, "foo")) + if err != nil { + c.Fatalf("failed to create foo file: %v", err) + } + defer testFile.Close() + + chownCmd := exec.Command("chown", "daemon:daemon", "foo") + chownCmd.Dir = tmpDir + out, _, err := runCommandWithOutput(chownCmd) + if err != nil { + c.Fatal(err, out) + } + + if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { + c.Fatalf("failed to open destination dockerfile: %v", err) + } + return fakeContextFromDir(tmpDir) + }() + + defer ctx.Close() + + if _, err := buildImageFromContext(name, ctx, true); err != nil { + c.Fatalf("build failed to complete for TestBuildAddChangeOwnership: %v", err) + } + +} + func (s *DockerSuite) TestBuildInheritance(c *check.C) { testRequires(c, DaemonIsLinux) name := "testbuildinheritance"