github.com/damirazo/docker@v1.9.0/integration-cli/docker_cli_cp_from_container_test.go (about)

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