github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/integration-cli/docker_cli_cp_test.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"os/exec"
     9  	"path"
    10  	"path/filepath"
    11  	"strings"
    12  
    13  	"github.com/docker/docker/integration-cli/checker"
    14  	"github.com/go-check/check"
    15  	"github.com/gotestyourself/gotestyourself/icmd"
    16  )
    17  
    18  const (
    19  	cpTestPathParent = "/some"
    20  	cpTestPath       = "/some/path"
    21  	cpTestName       = "test"
    22  	cpFullPath       = "/some/path/test"
    23  
    24  	cpContainerContents = "holla, i am the container"
    25  	cpHostContents      = "hello, i am the host"
    26  )
    27  
    28  // Ensure that an all-local path case returns an error.
    29  func (s *DockerSuite) TestCpLocalOnly(c *check.C) {
    30  	err := runDockerCp(c, "foo", "bar", nil)
    31  	c.Assert(err, checker.NotNil)
    32  
    33  	c.Assert(err.Error(), checker.Contains, "must specify at least one container source")
    34  }
    35  
    36  // Test for #5656
    37  // Check that garbage paths don't escape the container's rootfs
    38  func (s *DockerSuite) TestCpGarbagePath(c *check.C) {
    39  	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
    40  
    41  	containerID := strings.TrimSpace(out)
    42  
    43  	out, _ = dockerCmd(c, "wait", containerID)
    44  	// failed to set up container
    45  	c.Assert(strings.TrimSpace(out), checker.Equals, "0")
    46  
    47  	c.Assert(os.MkdirAll(cpTestPath, os.ModeDir), checker.IsNil)
    48  
    49  	hostFile, err := os.Create(cpFullPath)
    50  	c.Assert(err, checker.IsNil)
    51  	defer hostFile.Close()
    52  	defer os.RemoveAll(cpTestPathParent)
    53  
    54  	fmt.Fprintf(hostFile, "%s", cpHostContents)
    55  
    56  	tmpdir, err := ioutil.TempDir("", "docker-integration")
    57  	c.Assert(err, checker.IsNil)
    58  
    59  	tmpname := filepath.Join(tmpdir, cpTestName)
    60  	defer os.RemoveAll(tmpdir)
    61  
    62  	path := path.Join("../../../../../../../../../../../../", cpFullPath)
    63  
    64  	dockerCmd(c, "cp", containerID+":"+path, tmpdir)
    65  
    66  	file, _ := os.Open(tmpname)
    67  	defer file.Close()
    68  
    69  	test, err := ioutil.ReadAll(file)
    70  	c.Assert(err, checker.IsNil)
    71  
    72  	// output matched host file -- garbage path can escape container rootfs
    73  	c.Assert(string(test), checker.Not(checker.Equals), cpHostContents)
    74  
    75  	// output doesn't match the input for garbage path
    76  	c.Assert(string(test), checker.Equals, cpContainerContents)
    77  }
    78  
    79  // Check that relative paths are relative to the container's rootfs
    80  func (s *DockerSuite) TestCpRelativePath(c *check.C) {
    81  	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
    82  
    83  	containerID := strings.TrimSpace(out)
    84  
    85  	out, _ = dockerCmd(c, "wait", containerID)
    86  	// failed to set up container
    87  	c.Assert(strings.TrimSpace(out), checker.Equals, "0")
    88  
    89  	c.Assert(os.MkdirAll(cpTestPath, os.ModeDir), checker.IsNil)
    90  
    91  	hostFile, err := os.Create(cpFullPath)
    92  	c.Assert(err, checker.IsNil)
    93  	defer hostFile.Close()
    94  	defer os.RemoveAll(cpTestPathParent)
    95  
    96  	fmt.Fprintf(hostFile, "%s", cpHostContents)
    97  
    98  	tmpdir, err := ioutil.TempDir("", "docker-integration")
    99  	c.Assert(err, checker.IsNil)
   100  
   101  	tmpname := filepath.Join(tmpdir, cpTestName)
   102  	defer os.RemoveAll(tmpdir)
   103  
   104  	var relPath string
   105  	if path.IsAbs(cpFullPath) {
   106  		// normally this is `filepath.Rel("/", cpFullPath)` but we cannot
   107  		// get this unix-path manipulation on windows with filepath.
   108  		relPath = cpFullPath[1:]
   109  	}
   110  	c.Assert(path.IsAbs(cpFullPath), checker.True, check.Commentf("path %s was assumed to be an absolute path", cpFullPath))
   111  
   112  	dockerCmd(c, "cp", containerID+":"+relPath, tmpdir)
   113  
   114  	file, _ := os.Open(tmpname)
   115  	defer file.Close()
   116  
   117  	test, err := ioutil.ReadAll(file)
   118  	c.Assert(err, checker.IsNil)
   119  
   120  	// output matched host file -- relative path can escape container rootfs
   121  	c.Assert(string(test), checker.Not(checker.Equals), cpHostContents)
   122  
   123  	// output doesn't match the input for relative path
   124  	c.Assert(string(test), checker.Equals, cpContainerContents)
   125  }
   126  
   127  // Check that absolute paths are relative to the container's rootfs
   128  func (s *DockerSuite) TestCpAbsolutePath(c *check.C) {
   129  	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
   130  
   131  	containerID := strings.TrimSpace(out)
   132  
   133  	out, _ = dockerCmd(c, "wait", containerID)
   134  	// failed to set up container
   135  	c.Assert(strings.TrimSpace(out), checker.Equals, "0")
   136  
   137  	c.Assert(os.MkdirAll(cpTestPath, os.ModeDir), checker.IsNil)
   138  
   139  	hostFile, err := os.Create(cpFullPath)
   140  	c.Assert(err, checker.IsNil)
   141  	defer hostFile.Close()
   142  	defer os.RemoveAll(cpTestPathParent)
   143  
   144  	fmt.Fprintf(hostFile, "%s", cpHostContents)
   145  
   146  	tmpdir, err := ioutil.TempDir("", "docker-integration")
   147  	c.Assert(err, checker.IsNil)
   148  
   149  	tmpname := filepath.Join(tmpdir, cpTestName)
   150  	defer os.RemoveAll(tmpdir)
   151  
   152  	path := cpFullPath
   153  
   154  	dockerCmd(c, "cp", containerID+":"+path, tmpdir)
   155  
   156  	file, _ := os.Open(tmpname)
   157  	defer file.Close()
   158  
   159  	test, err := ioutil.ReadAll(file)
   160  	c.Assert(err, checker.IsNil)
   161  
   162  	// output matched host file -- absolute path can escape container rootfs
   163  	c.Assert(string(test), checker.Not(checker.Equals), cpHostContents)
   164  
   165  	// output doesn't match the input for absolute path
   166  	c.Assert(string(test), checker.Equals, cpContainerContents)
   167  }
   168  
   169  // Test for #5619
   170  // Check that absolute symlinks are still relative to the container's rootfs
   171  func (s *DockerSuite) TestCpAbsoluteSymlink(c *check.C) {
   172  	testRequires(c, DaemonIsLinux)
   173  	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpFullPath+" container_path")
   174  
   175  	containerID := strings.TrimSpace(out)
   176  
   177  	out, _ = dockerCmd(c, "wait", containerID)
   178  	// failed to set up container
   179  	c.Assert(strings.TrimSpace(out), checker.Equals, "0")
   180  
   181  	c.Assert(os.MkdirAll(cpTestPath, os.ModeDir), checker.IsNil)
   182  
   183  	hostFile, err := os.Create(cpFullPath)
   184  	c.Assert(err, checker.IsNil)
   185  	defer hostFile.Close()
   186  	defer os.RemoveAll(cpTestPathParent)
   187  
   188  	fmt.Fprintf(hostFile, "%s", cpHostContents)
   189  
   190  	tmpdir, err := ioutil.TempDir("", "docker-integration")
   191  	c.Assert(err, checker.IsNil)
   192  
   193  	tmpname := filepath.Join(tmpdir, "container_path")
   194  	defer os.RemoveAll(tmpdir)
   195  
   196  	path := path.Join("/", "container_path")
   197  
   198  	dockerCmd(c, "cp", containerID+":"+path, tmpdir)
   199  
   200  	// We should have copied a symlink *NOT* the file itself!
   201  	linkTarget, err := os.Readlink(tmpname)
   202  	c.Assert(err, checker.IsNil)
   203  
   204  	c.Assert(linkTarget, checker.Equals, filepath.FromSlash(cpFullPath))
   205  }
   206  
   207  // Check that symlinks to a directory behave as expected when copying one from
   208  // a container.
   209  func (s *DockerSuite) TestCpFromSymlinkToDirectory(c *check.C) {
   210  	testRequires(c, DaemonIsLinux)
   211  	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpTestPathParent+" /dir_link")
   212  
   213  	containerID := strings.TrimSpace(out)
   214  
   215  	out, _ = dockerCmd(c, "wait", containerID)
   216  	// failed to set up container
   217  	c.Assert(strings.TrimSpace(out), checker.Equals, "0")
   218  
   219  	testDir, err := ioutil.TempDir("", "test-cp-from-symlink-to-dir-")
   220  	c.Assert(err, checker.IsNil)
   221  	defer os.RemoveAll(testDir)
   222  
   223  	// This copy command should copy the symlink, not the target, into the
   224  	// temporary directory.
   225  	dockerCmd(c, "cp", containerID+":"+"/dir_link", testDir)
   226  
   227  	expectedPath := filepath.Join(testDir, "dir_link")
   228  	linkTarget, err := os.Readlink(expectedPath)
   229  	c.Assert(err, checker.IsNil)
   230  
   231  	c.Assert(linkTarget, checker.Equals, filepath.FromSlash(cpTestPathParent))
   232  
   233  	os.Remove(expectedPath)
   234  
   235  	// This copy command should resolve the symlink (note the trailing
   236  	// separator), copying the target into the temporary directory.
   237  	dockerCmd(c, "cp", containerID+":"+"/dir_link/", testDir)
   238  
   239  	// It *should not* have copied the directory using the target's name, but
   240  	// used the given name instead.
   241  	unexpectedPath := filepath.Join(testDir, cpTestPathParent)
   242  	stat, err := os.Lstat(unexpectedPath)
   243  	if err == nil {
   244  		out = fmt.Sprintf("target name was copied: %q - %q", stat.Mode(), stat.Name())
   245  	}
   246  	c.Assert(err, checker.NotNil, check.Commentf(out))
   247  
   248  	// It *should* have copied the directory using the asked name "dir_link".
   249  	stat, err = os.Lstat(expectedPath)
   250  	c.Assert(err, checker.IsNil, check.Commentf("unable to stat resource at %q", expectedPath))
   251  
   252  	c.Assert(stat.IsDir(), checker.True, check.Commentf("should have copied a directory but got %q instead", stat.Mode()))
   253  }
   254  
   255  // Check that symlinks to a directory behave as expected when copying one to a
   256  // container.
   257  func (s *DockerSuite) TestCpToSymlinkToDirectory(c *check.C) {
   258  	testRequires(c, DaemonIsLinux)
   259  	testRequires(c, SameHostDaemon) // Requires local volume mount bind.
   260  
   261  	testVol, err := ioutil.TempDir("", "test-cp-to-symlink-to-dir-")
   262  	c.Assert(err, checker.IsNil)
   263  	defer os.RemoveAll(testVol)
   264  
   265  	// Create a test container with a local volume. We will test by copying
   266  	// to the volume path in the container which we can then verify locally.
   267  	out, _ := dockerCmd(c, "create", "-v", testVol+":/testVol", "busybox")
   268  
   269  	containerID := strings.TrimSpace(out)
   270  
   271  	// Create a temp directory to hold a test file nested in a directory.
   272  	testDir, err := ioutil.TempDir("", "test-cp-to-symlink-to-dir-")
   273  	c.Assert(err, checker.IsNil)
   274  	defer os.RemoveAll(testDir)
   275  
   276  	// This file will be at "/testDir/some/path/test" and will be copied into
   277  	// the test volume later.
   278  	hostTestFilename := filepath.Join(testDir, cpFullPath)
   279  	c.Assert(os.MkdirAll(filepath.Dir(hostTestFilename), os.FileMode(0700)), checker.IsNil)
   280  	c.Assert(ioutil.WriteFile(hostTestFilename, []byte(cpHostContents), os.FileMode(0600)), checker.IsNil)
   281  
   282  	// Now create another temp directory to hold a symlink to the
   283  	// "/testDir/some" directory.
   284  	linkDir, err := ioutil.TempDir("", "test-cp-to-symlink-to-dir-")
   285  	c.Assert(err, checker.IsNil)
   286  	defer os.RemoveAll(linkDir)
   287  
   288  	// Then symlink "/linkDir/dir_link" to "/testdir/some".
   289  	linkTarget := filepath.Join(testDir, cpTestPathParent)
   290  	localLink := filepath.Join(linkDir, "dir_link")
   291  	c.Assert(os.Symlink(linkTarget, localLink), checker.IsNil)
   292  
   293  	// Now copy that symlink into the test volume in the container.
   294  	dockerCmd(c, "cp", localLink, containerID+":/testVol")
   295  
   296  	// This copy command should have copied the symlink *not* the target.
   297  	expectedPath := filepath.Join(testVol, "dir_link")
   298  	actualLinkTarget, err := os.Readlink(expectedPath)
   299  	c.Assert(err, checker.IsNil, check.Commentf("unable to read symlink at %q", expectedPath))
   300  
   301  	c.Assert(actualLinkTarget, checker.Equals, linkTarget)
   302  
   303  	// Good, now remove that copied link for the next test.
   304  	os.Remove(expectedPath)
   305  
   306  	// This copy command should resolve the symlink (note the trailing
   307  	// separator), copying the target into the test volume directory in the
   308  	// container.
   309  	dockerCmd(c, "cp", localLink+"/", containerID+":/testVol")
   310  
   311  	// It *should not* have copied the directory using the target's name, but
   312  	// used the given name instead.
   313  	unexpectedPath := filepath.Join(testVol, cpTestPathParent)
   314  	stat, err := os.Lstat(unexpectedPath)
   315  	if err == nil {
   316  		out = fmt.Sprintf("target name was copied: %q - %q", stat.Mode(), stat.Name())
   317  	}
   318  	c.Assert(err, checker.NotNil, check.Commentf(out))
   319  
   320  	// It *should* have copied the directory using the asked name "dir_link".
   321  	stat, err = os.Lstat(expectedPath)
   322  	c.Assert(err, checker.IsNil, check.Commentf("unable to stat resource at %q", expectedPath))
   323  
   324  	c.Assert(stat.IsDir(), checker.True, check.Commentf("should have copied a directory but got %q instead", stat.Mode()))
   325  
   326  	// And this directory should contain the file copied from the host at the
   327  	// expected location: "/testVol/dir_link/path/test"
   328  	expectedFilepath := filepath.Join(testVol, "dir_link/path/test")
   329  	fileContents, err := ioutil.ReadFile(expectedFilepath)
   330  	c.Assert(err, checker.IsNil)
   331  
   332  	c.Assert(string(fileContents), checker.Equals, cpHostContents)
   333  }
   334  
   335  // Test for #5619
   336  // Check that symlinks which are part of the resource path are still relative to the container's rootfs
   337  func (s *DockerSuite) TestCpSymlinkComponent(c *check.C) {
   338  	testRequires(c, DaemonIsLinux)
   339  	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpTestPath+" container_path")
   340  
   341  	containerID := strings.TrimSpace(out)
   342  
   343  	out, _ = dockerCmd(c, "wait", containerID)
   344  	// failed to set up container
   345  	c.Assert(strings.TrimSpace(out), checker.Equals, "0")
   346  
   347  	c.Assert(os.MkdirAll(cpTestPath, os.ModeDir), checker.IsNil)
   348  
   349  	hostFile, err := os.Create(cpFullPath)
   350  	c.Assert(err, checker.IsNil)
   351  	defer hostFile.Close()
   352  	defer os.RemoveAll(cpTestPathParent)
   353  
   354  	fmt.Fprintf(hostFile, "%s", cpHostContents)
   355  
   356  	tmpdir, err := ioutil.TempDir("", "docker-integration")
   357  
   358  	c.Assert(err, checker.IsNil)
   359  
   360  	tmpname := filepath.Join(tmpdir, cpTestName)
   361  	defer os.RemoveAll(tmpdir)
   362  
   363  	path := path.Join("/", "container_path", cpTestName)
   364  
   365  	dockerCmd(c, "cp", containerID+":"+path, tmpdir)
   366  
   367  	file, _ := os.Open(tmpname)
   368  	defer file.Close()
   369  
   370  	test, err := ioutil.ReadAll(file)
   371  	c.Assert(err, checker.IsNil)
   372  
   373  	// output matched host file -- symlink path component can escape container rootfs
   374  	c.Assert(string(test), checker.Not(checker.Equals), cpHostContents)
   375  
   376  	// output doesn't match the input for symlink path component
   377  	c.Assert(string(test), checker.Equals, cpContainerContents)
   378  }
   379  
   380  // Check that cp with unprivileged user doesn't return any error
   381  func (s *DockerSuite) TestCpUnprivilegedUser(c *check.C) {
   382  	testRequires(c, DaemonIsLinux, SameHostDaemon)
   383  	testRequires(c, UnixCli) // uses chmod/su: not available on windows
   384  
   385  	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "touch "+cpTestName)
   386  
   387  	containerID := strings.TrimSpace(out)
   388  
   389  	out, _ = dockerCmd(c, "wait", containerID)
   390  	// failed to set up container
   391  	c.Assert(strings.TrimSpace(out), checker.Equals, "0")
   392  
   393  	tmpdir, err := ioutil.TempDir("", "docker-integration")
   394  	c.Assert(err, checker.IsNil)
   395  
   396  	defer os.RemoveAll(tmpdir)
   397  
   398  	c.Assert(os.Chmod(tmpdir, 0777), checker.IsNil)
   399  
   400  	result := icmd.RunCommand("su", "unprivilegeduser", "-c",
   401  		fmt.Sprintf("%s cp %s:%s %s", dockerBinary, containerID, cpTestName, tmpdir))
   402  	result.Assert(c, icmd.Expected{})
   403  }
   404  
   405  func (s *DockerSuite) TestCpSpecialFiles(c *check.C) {
   406  	testRequires(c, DaemonIsLinux)
   407  	testRequires(c, SameHostDaemon)
   408  
   409  	outDir, err := ioutil.TempDir("", "cp-test-special-files")
   410  	c.Assert(err, checker.IsNil)
   411  	defer os.RemoveAll(outDir)
   412  
   413  	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "touch /foo")
   414  
   415  	containerID := strings.TrimSpace(out)
   416  
   417  	out, _ = dockerCmd(c, "wait", containerID)
   418  	// failed to set up container
   419  	c.Assert(strings.TrimSpace(out), checker.Equals, "0")
   420  
   421  	// Copy actual /etc/resolv.conf
   422  	dockerCmd(c, "cp", containerID+":/etc/resolv.conf", outDir)
   423  
   424  	expected := readContainerFile(c, containerID, "resolv.conf")
   425  	actual, err := ioutil.ReadFile(outDir + "/resolv.conf")
   426  
   427  	// Expected copied file to be duplicate of the container resolvconf
   428  	c.Assert(bytes.Equal(actual, expected), checker.True)
   429  
   430  	// Copy actual /etc/hosts
   431  	dockerCmd(c, "cp", containerID+":/etc/hosts", outDir)
   432  
   433  	expected = readContainerFile(c, containerID, "hosts")
   434  	actual, err = ioutil.ReadFile(outDir + "/hosts")
   435  
   436  	// Expected copied file to be duplicate of the container hosts
   437  	c.Assert(bytes.Equal(actual, expected), checker.True)
   438  
   439  	// Copy actual /etc/resolv.conf
   440  	dockerCmd(c, "cp", containerID+":/etc/hostname", outDir)
   441  
   442  	expected = readContainerFile(c, containerID, "hostname")
   443  	actual, err = ioutil.ReadFile(outDir + "/hostname")
   444  	c.Assert(err, checker.IsNil)
   445  
   446  	// Expected copied file to be duplicate of the container resolvconf
   447  	c.Assert(bytes.Equal(actual, expected), checker.True)
   448  }
   449  
   450  func (s *DockerSuite) TestCpVolumePath(c *check.C) {
   451  	//  stat /tmp/cp-test-volumepath851508420/test gets permission denied for the user
   452  	testRequires(c, NotUserNamespace)
   453  	testRequires(c, DaemonIsLinux)
   454  	testRequires(c, SameHostDaemon)
   455  
   456  	tmpDir, err := ioutil.TempDir("", "cp-test-volumepath")
   457  	c.Assert(err, checker.IsNil)
   458  	defer os.RemoveAll(tmpDir)
   459  	outDir, err := ioutil.TempDir("", "cp-test-volumepath-out")
   460  	c.Assert(err, checker.IsNil)
   461  	defer os.RemoveAll(outDir)
   462  	_, err = os.Create(tmpDir + "/test")
   463  	c.Assert(err, checker.IsNil)
   464  
   465  	out, _ := dockerCmd(c, "run", "-d", "-v", "/foo", "-v", tmpDir+"/test:/test", "-v", tmpDir+":/baz", "busybox", "/bin/sh", "-c", "touch /foo/bar")
   466  
   467  	containerID := strings.TrimSpace(out)
   468  
   469  	out, _ = dockerCmd(c, "wait", containerID)
   470  	// failed to set up container
   471  	c.Assert(strings.TrimSpace(out), checker.Equals, "0")
   472  
   473  	// Copy actual volume path
   474  	dockerCmd(c, "cp", containerID+":/foo", outDir)
   475  
   476  	stat, err := os.Stat(outDir + "/foo")
   477  	c.Assert(err, checker.IsNil)
   478  	// expected copied content to be dir
   479  	c.Assert(stat.IsDir(), checker.True)
   480  	stat, err = os.Stat(outDir + "/foo/bar")
   481  	c.Assert(err, checker.IsNil)
   482  	// Expected file `bar` to be a file
   483  	c.Assert(stat.IsDir(), checker.False)
   484  
   485  	// Copy file nested in volume
   486  	dockerCmd(c, "cp", containerID+":/foo/bar", outDir)
   487  
   488  	stat, err = os.Stat(outDir + "/bar")
   489  	c.Assert(err, checker.IsNil)
   490  	// Expected file `bar` to be a file
   491  	c.Assert(stat.IsDir(), checker.False)
   492  
   493  	// Copy Bind-mounted dir
   494  	dockerCmd(c, "cp", containerID+":/baz", outDir)
   495  	stat, err = os.Stat(outDir + "/baz")
   496  	c.Assert(err, checker.IsNil)
   497  	// Expected `baz` to be a dir
   498  	c.Assert(stat.IsDir(), checker.True)
   499  
   500  	// Copy file nested in bind-mounted dir
   501  	dockerCmd(c, "cp", containerID+":/baz/test", outDir)
   502  	fb, err := ioutil.ReadFile(outDir + "/baz/test")
   503  	c.Assert(err, checker.IsNil)
   504  	fb2, err := ioutil.ReadFile(tmpDir + "/test")
   505  	c.Assert(err, checker.IsNil)
   506  	// Expected copied file to be duplicate of bind-mounted file
   507  	c.Assert(bytes.Equal(fb, fb2), checker.True)
   508  
   509  	// Copy bind-mounted file
   510  	dockerCmd(c, "cp", containerID+":/test", outDir)
   511  	fb, err = ioutil.ReadFile(outDir + "/test")
   512  	c.Assert(err, checker.IsNil)
   513  	fb2, err = ioutil.ReadFile(tmpDir + "/test")
   514  	c.Assert(err, checker.IsNil)
   515  	// Expected copied file to be duplicate of bind-mounted file
   516  	c.Assert(bytes.Equal(fb, fb2), checker.True)
   517  }
   518  
   519  func (s *DockerSuite) TestCpToDot(c *check.C) {
   520  	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /test")
   521  
   522  	containerID := strings.TrimSpace(out)
   523  
   524  	out, _ = dockerCmd(c, "wait", containerID)
   525  	// failed to set up container
   526  	c.Assert(strings.TrimSpace(out), checker.Equals, "0")
   527  
   528  	tmpdir, err := ioutil.TempDir("", "docker-integration")
   529  	c.Assert(err, checker.IsNil)
   530  	defer os.RemoveAll(tmpdir)
   531  	cwd, err := os.Getwd()
   532  	c.Assert(err, checker.IsNil)
   533  	defer os.Chdir(cwd)
   534  	c.Assert(os.Chdir(tmpdir), checker.IsNil)
   535  	dockerCmd(c, "cp", containerID+":/test", ".")
   536  	content, err := ioutil.ReadFile("./test")
   537  	c.Assert(err, checker.IsNil)
   538  	c.Assert(string(content), checker.Equals, "lololol\n")
   539  }
   540  
   541  func (s *DockerSuite) TestCpToStdout(c *check.C) {
   542  	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /test")
   543  
   544  	containerID := strings.TrimSpace(out)
   545  
   546  	out, _ = dockerCmd(c, "wait", containerID)
   547  	// failed to set up container
   548  	c.Assert(strings.TrimSpace(out), checker.Equals, "0")
   549  
   550  	out, err := RunCommandPipelineWithOutput(
   551  		exec.Command(dockerBinary, "cp", containerID+":/test", "-"),
   552  		exec.Command("tar", "-vtf", "-"))
   553  
   554  	c.Assert(err, checker.IsNil)
   555  
   556  	c.Assert(out, checker.Contains, "test")
   557  	c.Assert(out, checker.Contains, "-rw")
   558  }
   559  
   560  func (s *DockerSuite) TestCpNameHasColon(c *check.C) {
   561  	testRequires(c, SameHostDaemon, DaemonIsLinux)
   562  
   563  	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /te:s:t")
   564  
   565  	containerID := strings.TrimSpace(out)
   566  
   567  	out, _ = dockerCmd(c, "wait", containerID)
   568  	// failed to set up container
   569  	c.Assert(strings.TrimSpace(out), checker.Equals, "0")
   570  
   571  	tmpdir, err := ioutil.TempDir("", "docker-integration")
   572  	c.Assert(err, checker.IsNil)
   573  	defer os.RemoveAll(tmpdir)
   574  	dockerCmd(c, "cp", containerID+":/te:s:t", tmpdir)
   575  	content, err := ioutil.ReadFile(tmpdir + "/te:s:t")
   576  	c.Assert(err, checker.IsNil)
   577  	c.Assert(string(content), checker.Equals, "lololol\n")
   578  }
   579  
   580  func (s *DockerSuite) TestCopyAndRestart(c *check.C) {
   581  	testRequires(c, DaemonIsLinux)
   582  	expectedMsg := "hello"
   583  	out, _ := dockerCmd(c, "run", "-d", "busybox", "echo", expectedMsg)
   584  	containerID := strings.TrimSpace(out)
   585  
   586  	out, _ = dockerCmd(c, "wait", containerID)
   587  	// failed to set up container
   588  	c.Assert(strings.TrimSpace(out), checker.Equals, "0")
   589  
   590  	tmpDir, err := ioutil.TempDir("", "test-docker-restart-after-copy-")
   591  	c.Assert(err, checker.IsNil)
   592  	defer os.RemoveAll(tmpDir)
   593  
   594  	dockerCmd(c, "cp", fmt.Sprintf("%s:/etc/group", containerID), tmpDir)
   595  
   596  	out, _ = dockerCmd(c, "start", "-a", containerID)
   597  
   598  	c.Assert(strings.TrimSpace(out), checker.Equals, expectedMsg)
   599  }
   600  
   601  func (s *DockerSuite) TestCopyCreatedContainer(c *check.C) {
   602  	testRequires(c, DaemonIsLinux)
   603  	dockerCmd(c, "create", "--name", "test_cp", "-v", "/test", "busybox")
   604  
   605  	tmpDir, err := ioutil.TempDir("", "test")
   606  	c.Assert(err, checker.IsNil)
   607  	defer os.RemoveAll(tmpDir)
   608  	dockerCmd(c, "cp", "test_cp:/bin/sh", tmpDir)
   609  }
   610  
   611  // test copy with option `-L`: following symbol link
   612  // Check that symlinks to a file behave as expected when copying one from
   613  // a container to host following symbol link
   614  func (s *DockerSuite) TestCpSymlinkFromConToHostFollowSymlink(c *check.C) {
   615  	testRequires(c, DaemonIsLinux)
   616  	out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpFullPath+" /dir_link")
   617  	if exitCode != 0 {
   618  		c.Fatal("failed to create a container", out)
   619  	}
   620  
   621  	cleanedContainerID := strings.TrimSpace(out)
   622  
   623  	out, _ = dockerCmd(c, "wait", cleanedContainerID)
   624  	if strings.TrimSpace(out) != "0" {
   625  		c.Fatal("failed to set up container", out)
   626  	}
   627  
   628  	testDir, err := ioutil.TempDir("", "test-cp-symlink-container-to-host-follow-symlink")
   629  	if err != nil {
   630  		c.Fatal(err)
   631  	}
   632  	defer os.RemoveAll(testDir)
   633  
   634  	// This copy command should copy the symlink, not the target, into the
   635  	// temporary directory.
   636  	dockerCmd(c, "cp", "-L", cleanedContainerID+":"+"/dir_link", testDir)
   637  
   638  	expectedPath := filepath.Join(testDir, "dir_link")
   639  
   640  	expected := []byte(cpContainerContents)
   641  	actual, err := ioutil.ReadFile(expectedPath)
   642  
   643  	if !bytes.Equal(actual, expected) {
   644  		c.Fatalf("Expected copied file to be duplicate of the container symbol link target")
   645  	}
   646  	os.Remove(expectedPath)
   647  
   648  	// now test copy symbol link to a non-existing file in host
   649  	expectedPath = filepath.Join(testDir, "somefile_host")
   650  	// expectedPath shouldn't exist, if exists, remove it
   651  	if _, err := os.Lstat(expectedPath); err == nil {
   652  		os.Remove(expectedPath)
   653  	}
   654  
   655  	dockerCmd(c, "cp", "-L", cleanedContainerID+":"+"/dir_link", expectedPath)
   656  
   657  	actual, err = ioutil.ReadFile(expectedPath)
   658  	c.Assert(err, checker.IsNil)
   659  
   660  	if !bytes.Equal(actual, expected) {
   661  		c.Fatalf("Expected copied file to be duplicate of the container symbol link target")
   662  	}
   663  	defer os.Remove(expectedPath)
   664  }