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