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