github.com/hustcat/docker@v1.3.3-0.20160314103604-901c67a8eeab/integration-cli/docker_cli_cp_to_container_test.go (about)

     1  package main
     2  
     3  import (
     4  	"os"
     5  
     6  	"github.com/docker/docker/pkg/integration/checker"
     7  	"github.com/go-check/check"
     8  )
     9  
    10  // docker cp LOCALPATH CONTAINER:PATH
    11  
    12  // Try all of the test cases from the archive package which implements the
    13  // internals of `docker cp` and ensure that the behavior matches when actually
    14  // copying to and from containers.
    15  
    16  // Basic assumptions about SRC and DST:
    17  // 1. SRC must exist.
    18  // 2. If SRC ends with a trailing separator, it must be a directory.
    19  // 3. DST parent directory must exist.
    20  // 4. If DST exists as a file, it must not end with a trailing separator.
    21  
    22  // First get these easy error cases out of the way.
    23  
    24  // Test for error when SRC does not exist.
    25  func (s *DockerSuite) TestCpToErrSrcNotExists(c *check.C) {
    26  	testRequires(c, DaemonIsLinux)
    27  	containerID := makeTestContainer(c, testContainerOptions{})
    28  
    29  	tmpDir := getTestDir(c, "test-cp-to-err-src-not-exists")
    30  	defer os.RemoveAll(tmpDir)
    31  
    32  	srcPath := cpPath(tmpDir, "file1")
    33  	dstPath := containerCpPath(containerID, "file1")
    34  
    35  	err := runDockerCp(c, srcPath, dstPath)
    36  	c.Assert(err, checker.NotNil)
    37  
    38  	c.Assert(isCpNotExist(err), checker.True, check.Commentf("expected IsNotExist error, but got %T: %s", err, err))
    39  }
    40  
    41  // Test for error when SRC ends in a trailing
    42  // path separator but it exists as a file.
    43  func (s *DockerSuite) TestCpToErrSrcNotDir(c *check.C) {
    44  	testRequires(c, DaemonIsLinux)
    45  	containerID := makeTestContainer(c, testContainerOptions{})
    46  
    47  	tmpDir := getTestDir(c, "test-cp-to-err-src-not-dir")
    48  	defer os.RemoveAll(tmpDir)
    49  
    50  	makeTestContentInDir(c, tmpDir)
    51  
    52  	srcPath := cpPathTrailingSep(tmpDir, "file1")
    53  	dstPath := containerCpPath(containerID, "testDir")
    54  
    55  	err := runDockerCp(c, srcPath, dstPath)
    56  	c.Assert(err, checker.NotNil)
    57  
    58  	c.Assert(isCpNotDir(err), checker.True, check.Commentf("expected IsNotDir error, but got %T: %s", err, err))
    59  }
    60  
    61  // Test for error when SRC is a valid file or directory,
    62  // bu the DST parent directory does not exist.
    63  func (s *DockerSuite) TestCpToErrDstParentNotExists(c *check.C) {
    64  	testRequires(c, DaemonIsLinux)
    65  	containerID := makeTestContainer(c, testContainerOptions{addContent: true})
    66  
    67  	tmpDir := getTestDir(c, "test-cp-to-err-dst-parent-not-exists")
    68  	defer os.RemoveAll(tmpDir)
    69  
    70  	makeTestContentInDir(c, tmpDir)
    71  
    72  	// Try with a file source.
    73  	srcPath := cpPath(tmpDir, "file1")
    74  	dstPath := containerCpPath(containerID, "/notExists", "file1")
    75  
    76  	err := runDockerCp(c, srcPath, dstPath)
    77  	c.Assert(err, checker.NotNil)
    78  
    79  	c.Assert(isCpNotExist(err), checker.True, check.Commentf("expected IsNotExist error, but got %T: %s", err, err))
    80  
    81  	// Try with a directory source.
    82  	srcPath = cpPath(tmpDir, "dir1")
    83  
    84  	c.Assert(err, checker.NotNil)
    85  
    86  	c.Assert(isCpNotExist(err), checker.True, check.Commentf("expected IsNotExist error, but got %T: %s", err, err))
    87  }
    88  
    89  // Test for error when DST ends in a trailing path separator but exists as a
    90  // file. Also test that we cannot overwrite an existing directory with a
    91  // non-directory and cannot overwrite an existing
    92  func (s *DockerSuite) TestCpToErrDstNotDir(c *check.C) {
    93  	testRequires(c, DaemonIsLinux)
    94  	containerID := makeTestContainer(c, testContainerOptions{addContent: true})
    95  
    96  	tmpDir := getTestDir(c, "test-cp-to-err-dst-not-dir")
    97  	defer os.RemoveAll(tmpDir)
    98  
    99  	makeTestContentInDir(c, tmpDir)
   100  
   101  	// Try with a file source.
   102  	srcPath := cpPath(tmpDir, "dir1/file1-1")
   103  	dstPath := containerCpPathTrailingSep(containerID, "file1")
   104  
   105  	// The client should encounter an error trying to stat the destination
   106  	// and then be unable to copy since the destination is asserted to be a
   107  	// directory but does not exist.
   108  	err := runDockerCp(c, srcPath, dstPath)
   109  	c.Assert(err, checker.NotNil)
   110  
   111  	c.Assert(isCpDirNotExist(err), checker.True, check.Commentf("expected DirNotExist error, but got %T: %s", err, err))
   112  
   113  	// Try with a directory source.
   114  	srcPath = cpPath(tmpDir, "dir1")
   115  
   116  	// The client should encounter an error trying to stat the destination and
   117  	// then decide to extract to the parent directory instead with a rebased
   118  	// name in the source archive, but this directory would overwrite the
   119  	// existing file with the same name.
   120  	err = runDockerCp(c, srcPath, dstPath)
   121  	c.Assert(err, checker.NotNil)
   122  
   123  	c.Assert(isCannotOverwriteNonDirWithDir(err), checker.True, check.Commentf("expected CannotOverwriteNonDirWithDir error, but got %T: %s", err, err))
   124  }
   125  
   126  // Check that copying from a local path to a symlink in a container copies to
   127  // the symlink target and does not overwrite the container symlink itself.
   128  func (s *DockerSuite) TestCpToSymlinkDestination(c *check.C) {
   129  	//  stat /tmp/test-cp-to-symlink-destination-262430901/vol3 gets permission denied for the user
   130  	testRequires(c, NotUserNamespace)
   131  	testRequires(c, DaemonIsLinux)
   132  	testRequires(c, SameHostDaemon) // Requires local volume mount bind.
   133  
   134  	testVol := getTestDir(c, "test-cp-to-symlink-destination-")
   135  	defer os.RemoveAll(testVol)
   136  
   137  	makeTestContentInDir(c, testVol)
   138  
   139  	containerID := makeTestContainer(c, testContainerOptions{
   140  		volumes: defaultVolumes(testVol), // Our bind mount is at /vol2
   141  	})
   142  
   143  	// First, copy a local file to a symlink to a file in the container. This
   144  	// should overwrite the symlink target contents with the source contents.
   145  	srcPath := cpPath(testVol, "file2")
   146  	dstPath := containerCpPath(containerID, "/vol2/symlinkToFile1")
   147  
   148  	c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil)
   149  
   150  	// The symlink should not have been modified.
   151  	c.Assert(symlinkTargetEquals(c, cpPath(testVol, "symlinkToFile1"), "file1"), checker.IsNil)
   152  
   153  	// The file should have the contents of "file2" now.
   154  	c.Assert(fileContentEquals(c, cpPath(testVol, "file1"), "file2\n"), checker.IsNil)
   155  
   156  	// Next, copy a local file to a symlink to a directory in the container.
   157  	// This should copy the file into the symlink target directory.
   158  	dstPath = containerCpPath(containerID, "/vol2/symlinkToDir1")
   159  
   160  	c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil)
   161  
   162  	// The symlink should not have been modified.
   163  	c.Assert(symlinkTargetEquals(c, cpPath(testVol, "symlinkToDir1"), "dir1"), checker.IsNil)
   164  
   165  	// The file should have the contents of "file2" now.
   166  	c.Assert(fileContentEquals(c, cpPath(testVol, "file2"), "file2\n"), checker.IsNil)
   167  
   168  	// Next, copy a file to a symlink to a file that does not exist (a broken
   169  	// symlink) in the container. This should create the target file with the
   170  	// contents of the source file.
   171  	dstPath = containerCpPath(containerID, "/vol2/brokenSymlinkToFileX")
   172  
   173  	c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil)
   174  
   175  	// The symlink should not have been modified.
   176  	c.Assert(symlinkTargetEquals(c, cpPath(testVol, "brokenSymlinkToFileX"), "fileX"), checker.IsNil)
   177  
   178  	// The file should have the contents of "file2" now.
   179  	c.Assert(fileContentEquals(c, cpPath(testVol, "fileX"), "file2\n"), checker.IsNil)
   180  
   181  	// Next, copy a local directory to a symlink to a directory in the
   182  	// container. This should copy the directory into the symlink target
   183  	// directory and not modify the symlink.
   184  	srcPath = cpPath(testVol, "/dir2")
   185  	dstPath = containerCpPath(containerID, "/vol2/symlinkToDir1")
   186  
   187  	c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil)
   188  
   189  	// The symlink should not have been modified.
   190  	c.Assert(symlinkTargetEquals(c, cpPath(testVol, "symlinkToDir1"), "dir1"), checker.IsNil)
   191  
   192  	// The directory should now contain a copy of "dir2".
   193  	c.Assert(fileContentEquals(c, cpPath(testVol, "dir1/dir2/file2-1"), "file2-1\n"), checker.IsNil)
   194  
   195  	// Next, copy a local directory to a symlink to a local directory that does
   196  	// not exist (a broken symlink) in the container. This should create the
   197  	// target as a directory with the contents of the source directory. It
   198  	// should not modify the symlink.
   199  	dstPath = containerCpPath(containerID, "/vol2/brokenSymlinkToDirX")
   200  
   201  	c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil)
   202  
   203  	// The symlink should not have been modified.
   204  	c.Assert(symlinkTargetEquals(c, cpPath(testVol, "brokenSymlinkToDirX"), "dirX"), checker.IsNil)
   205  
   206  	// The "dirX" directory should now be a copy of "dir2".
   207  	c.Assert(fileContentEquals(c, cpPath(testVol, "dirX/file2-1"), "file2-1\n"), checker.IsNil)
   208  }
   209  
   210  // Possibilities are reduced to the remaining 10 cases:
   211  //
   212  //  case | srcIsDir | onlyDirContents | dstExists | dstIsDir | dstTrSep | action
   213  // ===================================================================================================
   214  //   A   |  no      |  -              |  no       |  -       |  no      |  create file
   215  //   B   |  no      |  -              |  no       |  -       |  yes     |  error
   216  //   C   |  no      |  -              |  yes      |  no      |  -       |  overwrite file
   217  //   D   |  no      |  -              |  yes      |  yes     |  -       |  create file in dst dir
   218  //   E   |  yes     |  no             |  no       |  -       |  -       |  create dir, copy contents
   219  //   F   |  yes     |  no             |  yes      |  no      |  -       |  error
   220  //   G   |  yes     |  no             |  yes      |  yes     |  -       |  copy dir and contents
   221  //   H   |  yes     |  yes            |  no       |  -       |  -       |  create dir, copy contents
   222  //   I   |  yes     |  yes            |  yes      |  no      |  -       |  error
   223  //   J   |  yes     |  yes            |  yes      |  yes     |  -       |  copy dir contents
   224  //
   225  
   226  // A. SRC specifies a file and DST (no trailing path separator) doesn't
   227  //    exist. This should create a file with the name DST and copy the
   228  //    contents of the source file into it.
   229  func (s *DockerSuite) TestCpToCaseA(c *check.C) {
   230  	testRequires(c, DaemonIsLinux)
   231  	containerID := makeTestContainer(c, testContainerOptions{
   232  		workDir: "/root", command: makeCatFileCommand("itWorks.txt"),
   233  	})
   234  
   235  	tmpDir := getTestDir(c, "test-cp-to-case-a")
   236  	defer os.RemoveAll(tmpDir)
   237  
   238  	makeTestContentInDir(c, tmpDir)
   239  
   240  	srcPath := cpPath(tmpDir, "file1")
   241  	dstPath := containerCpPath(containerID, "/root/itWorks.txt")
   242  
   243  	c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil)
   244  
   245  	c.Assert(containerStartOutputEquals(c, containerID, "file1\n"), checker.IsNil)
   246  }
   247  
   248  // B. SRC specifies a file and DST (with trailing path separator) doesn't
   249  //    exist. This should cause an error because the copy operation cannot
   250  //    create a directory when copying a single file.
   251  func (s *DockerSuite) TestCpToCaseB(c *check.C) {
   252  	testRequires(c, DaemonIsLinux)
   253  	containerID := makeTestContainer(c, testContainerOptions{
   254  		command: makeCatFileCommand("testDir/file1"),
   255  	})
   256  
   257  	tmpDir := getTestDir(c, "test-cp-to-case-b")
   258  	defer os.RemoveAll(tmpDir)
   259  
   260  	makeTestContentInDir(c, tmpDir)
   261  
   262  	srcPath := cpPath(tmpDir, "file1")
   263  	dstDir := containerCpPathTrailingSep(containerID, "testDir")
   264  
   265  	err := runDockerCp(c, srcPath, dstDir)
   266  	c.Assert(err, checker.NotNil)
   267  
   268  	c.Assert(isCpDirNotExist(err), checker.True, check.Commentf("expected DirNotExists error, but got %T: %s", err, err))
   269  }
   270  
   271  // C. SRC specifies a file and DST exists as a file. This should overwrite
   272  //    the file at DST with the contents of the source file.
   273  func (s *DockerSuite) TestCpToCaseC(c *check.C) {
   274  	testRequires(c, DaemonIsLinux)
   275  	containerID := makeTestContainer(c, testContainerOptions{
   276  		addContent: true, workDir: "/root",
   277  		command: makeCatFileCommand("file2"),
   278  	})
   279  
   280  	tmpDir := getTestDir(c, "test-cp-to-case-c")
   281  	defer os.RemoveAll(tmpDir)
   282  
   283  	makeTestContentInDir(c, tmpDir)
   284  
   285  	srcPath := cpPath(tmpDir, "file1")
   286  	dstPath := containerCpPath(containerID, "/root/file2")
   287  
   288  	// Ensure the container's file starts with the original content.
   289  	c.Assert(containerStartOutputEquals(c, containerID, "file2\n"), checker.IsNil)
   290  
   291  	c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil)
   292  
   293  	// Should now contain file1's contents.
   294  	c.Assert(containerStartOutputEquals(c, containerID, "file1\n"), checker.IsNil)
   295  }
   296  
   297  // D. SRC specifies a file and DST exists as a directory. This should place
   298  //    a copy of the source file inside it using the basename from SRC. Ensure
   299  //    this works whether DST has a trailing path separator or not.
   300  func (s *DockerSuite) TestCpToCaseD(c *check.C) {
   301  	testRequires(c, DaemonIsLinux)
   302  	containerID := makeTestContainer(c, testContainerOptions{
   303  		addContent: true,
   304  		command:    makeCatFileCommand("/dir1/file1"),
   305  	})
   306  
   307  	tmpDir := getTestDir(c, "test-cp-to-case-d")
   308  	defer os.RemoveAll(tmpDir)
   309  
   310  	makeTestContentInDir(c, tmpDir)
   311  
   312  	srcPath := cpPath(tmpDir, "file1")
   313  	dstDir := containerCpPath(containerID, "dir1")
   314  
   315  	// Ensure that dstPath doesn't exist.
   316  	c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil)
   317  
   318  	c.Assert(runDockerCp(c, srcPath, dstDir), checker.IsNil)
   319  
   320  	// Should now contain file1's contents.
   321  	c.Assert(containerStartOutputEquals(c, containerID, "file1\n"), checker.IsNil)
   322  
   323  	// Now try again but using a trailing path separator for dstDir.
   324  
   325  	// Make new destination container.
   326  	containerID = makeTestContainer(c, testContainerOptions{
   327  		addContent: true,
   328  		command:    makeCatFileCommand("/dir1/file1"),
   329  	})
   330  
   331  	dstDir = containerCpPathTrailingSep(containerID, "dir1")
   332  
   333  	// Ensure that dstPath doesn't exist.
   334  	c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil)
   335  
   336  	c.Assert(runDockerCp(c, srcPath, dstDir), checker.IsNil)
   337  
   338  	// Should now contain file1's contents.
   339  	c.Assert(containerStartOutputEquals(c, containerID, "file1\n"), checker.IsNil)
   340  }
   341  
   342  // E. SRC specifies a directory and DST does not exist. This should create a
   343  //    directory at DST and copy the contents of the SRC directory into the DST
   344  //    directory. Ensure this works whether DST has a trailing path separator or
   345  //    not.
   346  func (s *DockerSuite) TestCpToCaseE(c *check.C) {
   347  	testRequires(c, DaemonIsLinux)
   348  	containerID := makeTestContainer(c, testContainerOptions{
   349  		command: makeCatFileCommand("/testDir/file1-1"),
   350  	})
   351  
   352  	tmpDir := getTestDir(c, "test-cp-to-case-e")
   353  	defer os.RemoveAll(tmpDir)
   354  
   355  	makeTestContentInDir(c, tmpDir)
   356  
   357  	srcDir := cpPath(tmpDir, "dir1")
   358  	dstDir := containerCpPath(containerID, "testDir")
   359  
   360  	c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil)
   361  
   362  	// Should now contain file1-1's contents.
   363  	c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil)
   364  
   365  	// Now try again but using a trailing path separator for dstDir.
   366  
   367  	// Make new destination container.
   368  	containerID = makeTestContainer(c, testContainerOptions{
   369  		command: makeCatFileCommand("/testDir/file1-1"),
   370  	})
   371  
   372  	dstDir = containerCpPathTrailingSep(containerID, "testDir")
   373  
   374  	c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil)
   375  
   376  	// Should now contain file1-1's contents.
   377  	c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil)
   378  }
   379  
   380  // F. SRC specifies a directory and DST exists as a file. This should cause an
   381  //    error as it is not possible to overwrite a file with a directory.
   382  func (s *DockerSuite) TestCpToCaseF(c *check.C) {
   383  	testRequires(c, DaemonIsLinux)
   384  	containerID := makeTestContainer(c, testContainerOptions{
   385  		addContent: true, workDir: "/root",
   386  	})
   387  
   388  	tmpDir := getTestDir(c, "test-cp-to-case-f")
   389  	defer os.RemoveAll(tmpDir)
   390  
   391  	makeTestContentInDir(c, tmpDir)
   392  
   393  	srcDir := cpPath(tmpDir, "dir1")
   394  	dstFile := containerCpPath(containerID, "/root/file1")
   395  
   396  	err := runDockerCp(c, srcDir, dstFile)
   397  	c.Assert(err, checker.NotNil)
   398  
   399  	c.Assert(isCpCannotCopyDir(err), checker.True, check.Commentf("expected ErrCannotCopyDir error, but got %T: %s", err, err))
   400  }
   401  
   402  // G. SRC specifies a directory and DST exists as a directory. This should copy
   403  //    the SRC directory and all its contents to the DST directory. Ensure this
   404  //    works whether DST has a trailing path separator or not.
   405  func (s *DockerSuite) TestCpToCaseG(c *check.C) {
   406  	testRequires(c, DaemonIsLinux)
   407  	containerID := makeTestContainer(c, testContainerOptions{
   408  		addContent: true, workDir: "/root",
   409  		command: makeCatFileCommand("dir2/dir1/file1-1"),
   410  	})
   411  
   412  	tmpDir := getTestDir(c, "test-cp-to-case-g")
   413  	defer os.RemoveAll(tmpDir)
   414  
   415  	makeTestContentInDir(c, tmpDir)
   416  
   417  	srcDir := cpPath(tmpDir, "dir1")
   418  	dstDir := containerCpPath(containerID, "/root/dir2")
   419  
   420  	// Ensure that dstPath doesn't exist.
   421  	c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil)
   422  
   423  	c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil)
   424  
   425  	// Should now contain file1-1's contents.
   426  	c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil)
   427  
   428  	// Now try again but using a trailing path separator for dstDir.
   429  
   430  	// Make new destination container.
   431  	containerID = makeTestContainer(c, testContainerOptions{
   432  		addContent: true,
   433  		command:    makeCatFileCommand("/dir2/dir1/file1-1"),
   434  	})
   435  
   436  	dstDir = containerCpPathTrailingSep(containerID, "/dir2")
   437  
   438  	// Ensure that dstPath doesn't exist.
   439  	c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil)
   440  
   441  	c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil)
   442  
   443  	// Should now contain file1-1's contents.
   444  	c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil)
   445  }
   446  
   447  // H. SRC specifies a directory's contents only and DST does not exist. This
   448  //    should create a directory at DST and copy the contents of the SRC
   449  //    directory (but not the directory itself) into the DST directory. Ensure
   450  //    this works whether DST has a trailing path separator or not.
   451  func (s *DockerSuite) TestCpToCaseH(c *check.C) {
   452  	testRequires(c, DaemonIsLinux)
   453  	containerID := makeTestContainer(c, testContainerOptions{
   454  		command: makeCatFileCommand("/testDir/file1-1"),
   455  	})
   456  
   457  	tmpDir := getTestDir(c, "test-cp-to-case-h")
   458  	defer os.RemoveAll(tmpDir)
   459  
   460  	makeTestContentInDir(c, tmpDir)
   461  
   462  	srcDir := cpPathTrailingSep(tmpDir, "dir1") + "."
   463  	dstDir := containerCpPath(containerID, "testDir")
   464  
   465  	c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil)
   466  
   467  	// Should now contain file1-1's contents.
   468  	c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil)
   469  
   470  	// Now try again but using a trailing path separator for dstDir.
   471  
   472  	// Make new destination container.
   473  	containerID = makeTestContainer(c, testContainerOptions{
   474  		command: makeCatFileCommand("/testDir/file1-1"),
   475  	})
   476  
   477  	dstDir = containerCpPathTrailingSep(containerID, "testDir")
   478  
   479  	c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil)
   480  
   481  	// Should now contain file1-1's contents.
   482  	c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil)
   483  }
   484  
   485  // I. SRC specifies a directory's contents only and DST exists as a file. This
   486  //    should cause an error as it is not possible to overwrite a file with a
   487  //    directory.
   488  func (s *DockerSuite) TestCpToCaseI(c *check.C) {
   489  	testRequires(c, DaemonIsLinux)
   490  	containerID := makeTestContainer(c, testContainerOptions{
   491  		addContent: true, workDir: "/root",
   492  	})
   493  
   494  	tmpDir := getTestDir(c, "test-cp-to-case-i")
   495  	defer os.RemoveAll(tmpDir)
   496  
   497  	makeTestContentInDir(c, tmpDir)
   498  
   499  	srcDir := cpPathTrailingSep(tmpDir, "dir1") + "."
   500  	dstFile := containerCpPath(containerID, "/root/file1")
   501  
   502  	err := runDockerCp(c, srcDir, dstFile)
   503  	c.Assert(err, checker.NotNil)
   504  
   505  	c.Assert(isCpCannotCopyDir(err), checker.True, check.Commentf("expected ErrCannotCopyDir error, but got %T: %s", err, err))
   506  }
   507  
   508  // J. SRC specifies a directory's contents only and DST exists as a directory.
   509  //    This should copy the contents of the SRC directory (but not the directory
   510  //    itself) into the DST directory. Ensure this works whether DST has a
   511  //    trailing path separator or not.
   512  func (s *DockerSuite) TestCpToCaseJ(c *check.C) {
   513  	testRequires(c, DaemonIsLinux)
   514  	containerID := makeTestContainer(c, testContainerOptions{
   515  		addContent: true, workDir: "/root",
   516  		command: makeCatFileCommand("/dir2/file1-1"),
   517  	})
   518  
   519  	tmpDir := getTestDir(c, "test-cp-to-case-j")
   520  	defer os.RemoveAll(tmpDir)
   521  
   522  	makeTestContentInDir(c, tmpDir)
   523  
   524  	srcDir := cpPathTrailingSep(tmpDir, "dir1") + "."
   525  	dstDir := containerCpPath(containerID, "/dir2")
   526  
   527  	// Ensure that dstPath doesn't exist.
   528  	c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil)
   529  
   530  	c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil)
   531  
   532  	// Should now contain file1-1's contents.
   533  	c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil)
   534  
   535  	// Now try again but using a trailing path separator for dstDir.
   536  
   537  	// Make new destination container.
   538  	containerID = makeTestContainer(c, testContainerOptions{
   539  		command: makeCatFileCommand("/dir2/file1-1"),
   540  	})
   541  
   542  	dstDir = containerCpPathTrailingSep(containerID, "/dir2")
   543  
   544  	// Ensure that dstPath doesn't exist.
   545  	c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil)
   546  
   547  	c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil)
   548  
   549  	// Should now contain file1-1's contents.
   550  	c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil)
   551  }
   552  
   553  // The `docker cp` command should also ensure that you cannot
   554  // write to a container rootfs that is marked as read-only.
   555  func (s *DockerSuite) TestCpToErrReadOnlyRootfs(c *check.C) {
   556  	// --read-only + userns has remount issues
   557  	testRequires(c, DaemonIsLinux, NotUserNamespace)
   558  	tmpDir := getTestDir(c, "test-cp-to-err-read-only-rootfs")
   559  	defer os.RemoveAll(tmpDir)
   560  
   561  	makeTestContentInDir(c, tmpDir)
   562  
   563  	containerID := makeTestContainer(c, testContainerOptions{
   564  		readOnly: true, workDir: "/root",
   565  		command: makeCatFileCommand("shouldNotExist"),
   566  	})
   567  
   568  	srcPath := cpPath(tmpDir, "file1")
   569  	dstPath := containerCpPath(containerID, "/root/shouldNotExist")
   570  
   571  	err := runDockerCp(c, srcPath, dstPath)
   572  	c.Assert(err, checker.NotNil)
   573  
   574  	c.Assert(isCpCannotCopyReadOnly(err), checker.True, check.Commentf("expected ErrContainerRootfsReadonly error, but got %T: %s", err, err))
   575  
   576  	// Ensure that dstPath doesn't exist.
   577  	c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil)
   578  }
   579  
   580  // The `docker cp` command should also ensure that you
   581  // cannot write to a volume that is mounted as read-only.
   582  func (s *DockerSuite) TestCpToErrReadOnlyVolume(c *check.C) {
   583  	// --read-only + userns has remount issues
   584  	testRequires(c, DaemonIsLinux, NotUserNamespace)
   585  	tmpDir := getTestDir(c, "test-cp-to-err-read-only-volume")
   586  	defer os.RemoveAll(tmpDir)
   587  
   588  	makeTestContentInDir(c, tmpDir)
   589  
   590  	containerID := makeTestContainer(c, testContainerOptions{
   591  		volumes: defaultVolumes(tmpDir), workDir: "/root",
   592  		command: makeCatFileCommand("/vol_ro/shouldNotExist"),
   593  	})
   594  
   595  	srcPath := cpPath(tmpDir, "file1")
   596  	dstPath := containerCpPath(containerID, "/vol_ro/shouldNotExist")
   597  
   598  	err := runDockerCp(c, srcPath, dstPath)
   599  	c.Assert(err, checker.NotNil)
   600  
   601  	c.Assert(isCpCannotCopyReadOnly(err), checker.True, check.Commentf("expected ErrVolumeReadonly error, but got %T: %s", err, err))
   602  
   603  	// Ensure that dstPath doesn't exist.
   604  	c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil)
   605  }