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