github.com/noxiouz/docker@v0.7.3-0.20160629055221-3d231c78e8c5/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 }