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