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