Browse Source

Change owner only on copied content

Fixes #5110
Docker-DCO-1.1-Signed-off-by: Alexandr Morozov <lk4d4math@gmail.com> (github: LK4D4)
LK4D4 11 năm trước cách đây
mục cha
commit
91b7d8ebd3

+ 3 - 0
archive/archive.go

@@ -418,6 +418,9 @@ func Untar(archive io.Reader, dest string, options *TarOptions) error {
 		// the layer is also a directory. Then we want to merge them (i.e.
 		// just apply the metadata from the layer).
 		if fi, err := os.Lstat(path); err == nil {
+			if fi.IsDir() && hdr.Name == "." {
+				continue
+			}
 			if !(fi.IsDir() && hdr.Typeflag == tar.TypeDir) {
 				if err := os.RemoveAll(path); err != nil {
 					return err

+ 10 - 0
integration-cli/build_tests/TestAdd/DirContentToExistDir/Dockerfile

@@ -0,0 +1,10 @@
+FROM busybox
+RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
+RUN echo 'dockerio:x:1001:' >> /etc/group
+RUN mkdir /exists
+RUN touch /exists/exists_file
+RUN chown -R dockerio.dockerio /exists
+ADD test_dir/ /exists/
+RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
+RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
+RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]

+ 0 - 0
integration-cli/build_tests/TestAdd/DirContentToExistDir/test_dir/test_file


+ 8 - 0
integration-cli/build_tests/TestAdd/DirContentToRoot/Dockerfile

@@ -0,0 +1,8 @@
+FROM busybox
+RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
+RUN echo 'dockerio:x:1001:' >> /etc/group
+RUN touch /exists
+RUN chown dockerio.dockerio exists
+ADD test_dir /
+RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ]
+RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]

+ 0 - 0
integration-cli/build_tests/TestAdd/DirContentToRoot/test_dir/test_file


+ 10 - 0
integration-cli/build_tests/TestAdd/SingleFileToExistDir/Dockerfile

@@ -0,0 +1,10 @@
+FROM busybox
+RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
+RUN echo 'dockerio:x:1001:' >> /etc/group
+RUN mkdir /exists
+RUN touch /exists/exists_file
+RUN chown -R dockerio.dockerio /exists
+ADD test_file /exists/
+RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
+RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]
+RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]

+ 0 - 0
integration-cli/build_tests/TestAdd/SingleFileToExistDir/test_file


+ 9 - 0
integration-cli/build_tests/TestAdd/SingleFileToNonExistDir/Dockerfile

@@ -0,0 +1,9 @@
+FROM busybox
+RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
+RUN echo 'dockerio:x:1001:' >> /etc/group
+RUN touch /exists
+RUN chown dockerio.dockerio /exists
+ADD test_file /test_dir/
+RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ]
+RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ]
+RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]

+ 0 - 0
integration-cli/build_tests/TestAdd/SingleFileToNonExistDir/test_file


+ 8 - 0
integration-cli/build_tests/TestAdd/SingleFileToRoot/Dockerfile

@@ -0,0 +1,8 @@
+FROM busybox
+RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
+RUN echo 'dockerio:x:1001:' >> /etc/group
+RUN touch /exists
+RUN chown dockerio.dockerio /exists
+ADD test_file /
+RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ]
+RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]

+ 0 - 0
integration-cli/build_tests/TestAdd/SingleFileToRoot/test_file


+ 9 - 0
integration-cli/build_tests/TestAdd/WholeDirToRoot/Dockerfile

@@ -0,0 +1,9 @@
+FROM busybox
+RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
+RUN echo 'dockerio:x:1001:' >> /etc/group
+RUN touch /exists
+RUN chown dockerio.dockerio exists
+ADD test_dir /test_dir
+RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ]
+RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ]
+RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]

+ 0 - 0
integration-cli/build_tests/TestAdd/WholeDirToRoot/test_dir/test_file


+ 96 - 0
integration-cli/docker_cli_build_test.go

@@ -23,6 +23,102 @@ func TestBuildSixtySteps(t *testing.T) {
 	logDone("build - build an image with sixty build steps")
 }
 
+func TestAddSingleFileToRoot(t *testing.T) {
+	buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestAdd")
+	buildCmd := exec.Command(dockerBinary, "build", "-t", "testaddimg", "SingleFileToRoot")
+	buildCmd.Dir = buildDirectory
+	out, exitCode, err := runCommandWithOutput(buildCmd)
+	errorOut(err, t, fmt.Sprintf("build failed to complete: %v %v", out, err))
+
+	if err != nil || exitCode != 0 {
+		t.Fatal("failed to build the image")
+	}
+
+	deleteImages("testaddimg")
+
+	logDone("build - add single file to root")
+}
+
+func TestAddSingleFileToExistDir(t *testing.T) {
+	buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestAdd")
+	buildCmd := exec.Command(dockerBinary, "build", "-t", "testaddimg", "SingleFileToExistDir")
+	buildCmd.Dir = buildDirectory
+	out, exitCode, err := runCommandWithOutput(buildCmd)
+	errorOut(err, t, fmt.Sprintf("build failed to complete: %v %v", out, err))
+
+	if err != nil || exitCode != 0 {
+		t.Fatal("failed to build the image")
+	}
+
+	deleteImages("testaddimg")
+
+	logDone("build - add single file to existing dir")
+}
+
+func TestAddSingleFileToNonExistDir(t *testing.T) {
+	buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestAdd")
+	buildCmd := exec.Command(dockerBinary, "build", "-t", "testaddimg", "SingleFileToNonExistDir")
+	buildCmd.Dir = buildDirectory
+	out, exitCode, err := runCommandWithOutput(buildCmd)
+	errorOut(err, t, fmt.Sprintf("build failed to complete: %v %v", out, err))
+
+	if err != nil || exitCode != 0 {
+		t.Fatal("failed to build the image")
+	}
+
+	deleteImages("testaddimg")
+
+	logDone("build - add single file to non-existing dir")
+}
+
+func TestAddDirContentToRoot(t *testing.T) {
+	buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestAdd")
+	buildCmd := exec.Command(dockerBinary, "build", "-t", "testaddimg", "DirContentToRoot")
+	buildCmd.Dir = buildDirectory
+	out, exitCode, err := runCommandWithOutput(buildCmd)
+	errorOut(err, t, fmt.Sprintf("build failed to complete: %v %v", out, err))
+
+	if err != nil || exitCode != 0 {
+		t.Fatal("failed to build the image")
+	}
+
+	deleteImages("testaddimg")
+
+	logDone("build - add directory contents to root")
+}
+
+func TestAddDirContentToExistDir(t *testing.T) {
+	buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestAdd")
+	buildCmd := exec.Command(dockerBinary, "build", "-t", "testaddimg", "DirContentToExistDir")
+	buildCmd.Dir = buildDirectory
+	out, exitCode, err := runCommandWithOutput(buildCmd)
+	errorOut(err, t, fmt.Sprintf("build failed to complete: %v %v", out, err))
+
+	if err != nil || exitCode != 0 {
+		t.Fatal("failed to build the image")
+	}
+
+	deleteImages("testaddimg")
+
+	logDone("build - add directory contents to existing dir")
+}
+
+func TestAddWholeDirToRoot(t *testing.T) {
+	buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestAdd")
+	buildCmd := exec.Command(dockerBinary, "build", "-t", "testaddimg", "WholeDirToRoot")
+	buildCmd.Dir = buildDirectory
+	out, exitCode, err := runCommandWithOutput(buildCmd)
+	errorOut(err, t, fmt.Sprintf("build failed to complete: %v %v", out, err))
+
+	if err != nil || exitCode != 0 {
+		t.Fatal("failed to build the image")
+	}
+
+	deleteImages("testaddimg")
+
+	logDone("build - add whole directory to root")
+}
+
 // TODO: TestCaching
 
 // TODO: TestADDCacheInvalidation

+ 32 - 6
server/buildfile.go

@@ -386,9 +386,10 @@ func (b *buildFile) checkPathForAddition(orig string) error {
 
 func (b *buildFile) addContext(container *daemon.Container, orig, dest string, remote bool) error {
 	var (
-		err      error
-		origPath = path.Join(b.contextPath, orig)
-		destPath = path.Join(container.RootfsPath(), dest)
+		err        error
+		destExists = true
+		origPath   = path.Join(b.contextPath, orig)
+		destPath   = path.Join(container.RootfsPath(), dest)
 	)
 
 	if destPath != container.RootfsPath() {
@@ -402,6 +403,14 @@ func (b *buildFile) addContext(container *daemon.Container, orig, dest string, r
 	if strings.HasSuffix(dest, "/") {
 		destPath = destPath + "/"
 	}
+	destStat, err := os.Stat(destPath)
+	if err != nil {
+		if os.IsNotExist(err) {
+			destExists = false
+		} else {
+			return err
+		}
+	}
 	fi, err := os.Stat(origPath)
 	if err != nil {
 		if os.IsNotExist(err) {
@@ -423,8 +432,20 @@ func (b *buildFile) addContext(container *daemon.Container, orig, dest string, r
 		if err := archive.CopyWithTar(origPath, destPath); err != nil {
 			return err
 		}
-		if err := chownR(destPath, 0, 0); err != nil {
-			return err
+		if destExists {
+			files, err := ioutil.ReadDir(origPath)
+			if err != nil {
+				return err
+			}
+			for _, file := range files {
+				if err := chownR(filepath.Join(destPath, file.Name()), 0, 0); err != nil {
+					return err
+				}
+			}
+		} else {
+			if err := chownR(destPath, 0, 0); err != nil {
+				return err
+			}
 		}
 		return nil
 	}
@@ -456,7 +477,12 @@ func (b *buildFile) addContext(container *daemon.Container, orig, dest string, r
 		return err
 	}
 
-	if err := chownR(destPath, 0, 0); err != nil {
+	resPath := destPath
+	if destExists && destStat.IsDir() {
+		resPath = path.Join(destPath, path.Base(origPath))
+	}
+
+	if err := chownR(resPath, 0, 0); err != nil {
 		return err
 	}
 	return nil