github.com/samsalisbury/docker@v1.9.0/integration-cli/docker_cli_cp_test.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "os/exec" 9 "path" 10 "path/filepath" 11 "strings" 12 13 "github.com/go-check/check" 14 ) 15 16 const ( 17 cpTestPathParent = "/some" 18 cpTestPath = "/some/path" 19 cpTestName = "test" 20 cpFullPath = "/some/path/test" 21 22 cpContainerContents = "holla, i am the container" 23 cpHostContents = "hello, i am the host" 24 ) 25 26 // Ensure that an all-local path case returns an error. 27 func (s *DockerSuite) TestCpLocalOnly(c *check.C) { 28 err := runDockerCp(c, "foo", "bar") 29 if err == nil { 30 c.Fatal("expected failure, got success") 31 } 32 33 if !strings.Contains(err.Error(), "must specify at least one container source") { 34 c.Fatalf("unexpected output: %s", err.Error()) 35 } 36 } 37 38 // Test for #5656 39 // Check that garbage paths don't escape the container's rootfs 40 func (s *DockerSuite) TestCpGarbagePath(c *check.C) { 41 testRequires(c, DaemonIsLinux) 42 out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath) 43 if exitCode != 0 { 44 c.Fatal("failed to create a container", out) 45 } 46 47 cleanedContainerID := strings.TrimSpace(out) 48 49 out, _ = dockerCmd(c, "wait", cleanedContainerID) 50 if strings.TrimSpace(out) != "0" { 51 c.Fatal("failed to set up container", out) 52 } 53 54 if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil { 55 c.Fatal(err) 56 } 57 58 hostFile, err := os.Create(cpFullPath) 59 if err != nil { 60 c.Fatal(err) 61 } 62 defer hostFile.Close() 63 defer os.RemoveAll(cpTestPathParent) 64 65 fmt.Fprintf(hostFile, "%s", cpHostContents) 66 67 tmpdir, err := ioutil.TempDir("", "docker-integration") 68 if err != nil { 69 c.Fatal(err) 70 } 71 72 tmpname := filepath.Join(tmpdir, cpTestName) 73 defer os.RemoveAll(tmpdir) 74 75 path := path.Join("../../../../../../../../../../../../", cpFullPath) 76 77 dockerCmd(c, "cp", cleanedContainerID+":"+path, tmpdir) 78 79 file, _ := os.Open(tmpname) 80 defer file.Close() 81 82 test, err := ioutil.ReadAll(file) 83 if err != nil { 84 c.Fatal(err) 85 } 86 87 if string(test) == cpHostContents { 88 c.Errorf("output matched host file -- garbage path can escape container rootfs") 89 } 90 91 if string(test) != cpContainerContents { 92 c.Errorf("output doesn't match the input for garbage path") 93 } 94 95 } 96 97 // Check that relative paths are relative to the container's rootfs 98 func (s *DockerSuite) TestCpRelativePath(c *check.C) { 99 testRequires(c, DaemonIsLinux) 100 out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath) 101 if exitCode != 0 { 102 c.Fatal("failed to create a container", out) 103 } 104 105 cleanedContainerID := strings.TrimSpace(out) 106 107 out, _ = dockerCmd(c, "wait", cleanedContainerID) 108 if strings.TrimSpace(out) != "0" { 109 c.Fatal("failed to set up container", out) 110 } 111 112 if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil { 113 c.Fatal(err) 114 } 115 116 hostFile, err := os.Create(cpFullPath) 117 if err != nil { 118 c.Fatal(err) 119 } 120 defer hostFile.Close() 121 defer os.RemoveAll(cpTestPathParent) 122 123 fmt.Fprintf(hostFile, "%s", cpHostContents) 124 125 tmpdir, err := ioutil.TempDir("", "docker-integration") 126 127 if err != nil { 128 c.Fatal(err) 129 } 130 131 tmpname := filepath.Join(tmpdir, cpTestName) 132 defer os.RemoveAll(tmpdir) 133 134 var relPath string 135 if path.IsAbs(cpFullPath) { 136 // normally this is `filepath.Rel("/", cpFullPath)` but we cannot 137 // get this unix-path manipulation on windows with filepath. 138 relPath = cpFullPath[1:] 139 } else { 140 c.Fatalf("path %s was assumed to be an absolute path", cpFullPath) 141 } 142 143 dockerCmd(c, "cp", cleanedContainerID+":"+relPath, tmpdir) 144 145 file, _ := os.Open(tmpname) 146 defer file.Close() 147 148 test, err := ioutil.ReadAll(file) 149 if err != nil { 150 c.Fatal(err) 151 } 152 153 if string(test) == cpHostContents { 154 c.Errorf("output matched host file -- relative path can escape container rootfs") 155 } 156 157 if string(test) != cpContainerContents { 158 c.Errorf("output doesn't match the input for relative path") 159 } 160 161 } 162 163 // Check that absolute paths are relative to the container's rootfs 164 func (s *DockerSuite) TestCpAbsolutePath(c *check.C) { 165 testRequires(c, DaemonIsLinux) 166 out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath) 167 if exitCode != 0 { 168 c.Fatal("failed to create a container", out) 169 } 170 171 cleanedContainerID := strings.TrimSpace(out) 172 173 out, _ = dockerCmd(c, "wait", cleanedContainerID) 174 if strings.TrimSpace(out) != "0" { 175 c.Fatal("failed to set up container", out) 176 } 177 178 if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil { 179 c.Fatal(err) 180 } 181 182 hostFile, err := os.Create(cpFullPath) 183 if err != nil { 184 c.Fatal(err) 185 } 186 defer hostFile.Close() 187 defer os.RemoveAll(cpTestPathParent) 188 189 fmt.Fprintf(hostFile, "%s", cpHostContents) 190 191 tmpdir, err := ioutil.TempDir("", "docker-integration") 192 193 if err != nil { 194 c.Fatal(err) 195 } 196 197 tmpname := filepath.Join(tmpdir, cpTestName) 198 defer os.RemoveAll(tmpdir) 199 200 path := cpFullPath 201 202 dockerCmd(c, "cp", cleanedContainerID+":"+path, tmpdir) 203 204 file, _ := os.Open(tmpname) 205 defer file.Close() 206 207 test, err := ioutil.ReadAll(file) 208 if err != nil { 209 c.Fatal(err) 210 } 211 212 if string(test) == cpHostContents { 213 c.Errorf("output matched host file -- absolute path can escape container rootfs") 214 } 215 216 if string(test) != cpContainerContents { 217 c.Errorf("output doesn't match the input for absolute path") 218 } 219 220 } 221 222 // Test for #5619 223 // Check that absolute symlinks are still relative to the container's rootfs 224 func (s *DockerSuite) TestCpAbsoluteSymlink(c *check.C) { 225 testRequires(c, DaemonIsLinux) 226 out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpFullPath+" container_path") 227 if exitCode != 0 { 228 c.Fatal("failed to create a container", out) 229 } 230 231 cleanedContainerID := strings.TrimSpace(out) 232 233 out, _ = dockerCmd(c, "wait", cleanedContainerID) 234 if strings.TrimSpace(out) != "0" { 235 c.Fatal("failed to set up container", out) 236 } 237 238 if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil { 239 c.Fatal(err) 240 } 241 242 hostFile, err := os.Create(cpFullPath) 243 if err != nil { 244 c.Fatal(err) 245 } 246 defer hostFile.Close() 247 defer os.RemoveAll(cpTestPathParent) 248 249 fmt.Fprintf(hostFile, "%s", cpHostContents) 250 251 tmpdir, err := ioutil.TempDir("", "docker-integration") 252 253 if err != nil { 254 c.Fatal(err) 255 } 256 257 tmpname := filepath.Join(tmpdir, "container_path") 258 defer os.RemoveAll(tmpdir) 259 260 path := path.Join("/", "container_path") 261 262 dockerCmd(c, "cp", cleanedContainerID+":"+path, tmpdir) 263 264 // We should have copied a symlink *NOT* the file itself! 265 linkTarget, err := os.Readlink(tmpname) 266 if err != nil { 267 c.Fatal(err) 268 } 269 270 if linkTarget != filepath.FromSlash(cpFullPath) { 271 c.Errorf("symlink target was %q, but expected: %q", linkTarget, cpFullPath) 272 } 273 } 274 275 // Check that symlinks to a directory behave as expected when copying one from 276 // a container. 277 func (s *DockerSuite) TestCpFromSymlinkToDirectory(c *check.C) { 278 testRequires(c, DaemonIsLinux) 279 out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpTestPathParent+" /dir_link") 280 if exitCode != 0 { 281 c.Fatal("failed to create a container", out) 282 } 283 284 cleanedContainerID := strings.TrimSpace(out) 285 286 out, _ = dockerCmd(c, "wait", cleanedContainerID) 287 if strings.TrimSpace(out) != "0" { 288 c.Fatal("failed to set up container", out) 289 } 290 291 testDir, err := ioutil.TempDir("", "test-cp-from-symlink-to-dir-") 292 if err != nil { 293 c.Fatal(err) 294 } 295 defer os.RemoveAll(testDir) 296 297 // This copy command should copy the symlink, not the target, into the 298 // temporary directory. 299 dockerCmd(c, "cp", cleanedContainerID+":"+"/dir_link", testDir) 300 301 expectedPath := filepath.Join(testDir, "dir_link") 302 linkTarget, err := os.Readlink(expectedPath) 303 if err != nil { 304 c.Fatalf("unable to read symlink at %q: %v", expectedPath, err) 305 } 306 307 if linkTarget != filepath.FromSlash(cpTestPathParent) { 308 c.Errorf("symlink target was %q, but expected: %q", linkTarget, cpTestPathParent) 309 } 310 311 os.Remove(expectedPath) 312 313 // This copy command should resolve the symlink (note the trailing 314 // separator), copying the target into the temporary directory. 315 dockerCmd(c, "cp", cleanedContainerID+":"+"/dir_link/", testDir) 316 317 // It *should not* have copied the directory using the target's name, but 318 // used the given name instead. 319 unexpectedPath := filepath.Join(testDir, cpTestPathParent) 320 if stat, err := os.Lstat(unexpectedPath); err == nil { 321 c.Fatalf("target name was copied: %q - %q", stat.Mode(), stat.Name()) 322 } 323 324 // It *should* have copied the directory using the asked name "dir_link". 325 stat, err := os.Lstat(expectedPath) 326 if err != nil { 327 c.Fatalf("unable to stat resource at %q: %v", expectedPath, err) 328 } 329 330 if !stat.IsDir() { 331 c.Errorf("should have copied a directory but got %q instead", stat.Mode()) 332 } 333 } 334 335 // Check that symlinks to a directory behave as expected when copying one to a 336 // container. 337 func (s *DockerSuite) TestCpToSymlinkToDirectory(c *check.C) { 338 testRequires(c, DaemonIsLinux) 339 testRequires(c, SameHostDaemon) // Requires local volume mount bind. 340 341 testVol, err := ioutil.TempDir("", "test-cp-to-symlink-to-dir-") 342 if err != nil { 343 c.Fatal(err) 344 } 345 defer os.RemoveAll(testVol) 346 347 // Create a test container with a local volume. We will test by copying 348 // to the volume path in the container which we can then verify locally. 349 out, exitCode := dockerCmd(c, "create", "-v", testVol+":/testVol", "busybox") 350 if exitCode != 0 { 351 c.Fatal("failed to create a container", out) 352 } 353 354 cleanedContainerID := strings.TrimSpace(out) 355 356 // Create a temp directory to hold a test file nested in a direcotry. 357 testDir, err := ioutil.TempDir("", "test-cp-to-symlink-to-dir-") 358 if err != nil { 359 c.Fatal(err) 360 } 361 defer os.RemoveAll(testDir) 362 363 // This file will be at "/testDir/some/path/test" and will be copied into 364 // the test volume later. 365 hostTestFilename := filepath.Join(testDir, cpFullPath) 366 if err := os.MkdirAll(filepath.Dir(hostTestFilename), os.FileMode(0700)); err != nil { 367 c.Fatal(err) 368 } 369 if err := ioutil.WriteFile(hostTestFilename, []byte(cpHostContents), os.FileMode(0600)); err != nil { 370 c.Fatal(err) 371 } 372 373 // Now create another temp directory to hold a symlink to the 374 // "/testDir/some" directory. 375 linkDir, err := ioutil.TempDir("", "test-cp-to-symlink-to-dir-") 376 if err != nil { 377 c.Fatal(err) 378 } 379 defer os.RemoveAll(linkDir) 380 381 // Then symlink "/linkDir/dir_link" to "/testdir/some". 382 linkTarget := filepath.Join(testDir, cpTestPathParent) 383 localLink := filepath.Join(linkDir, "dir_link") 384 if err := os.Symlink(linkTarget, localLink); err != nil { 385 c.Fatal(err) 386 } 387 388 // Now copy that symlink into the test volume in the container. 389 dockerCmd(c, "cp", localLink, cleanedContainerID+":/testVol") 390 391 // This copy command should have copied the symlink *not* the target. 392 expectedPath := filepath.Join(testVol, "dir_link") 393 actualLinkTarget, err := os.Readlink(expectedPath) 394 if err != nil { 395 c.Fatalf("unable to read symlink at %q: %v", expectedPath, err) 396 } 397 398 if actualLinkTarget != linkTarget { 399 c.Errorf("symlink target was %q, but expected: %q", actualLinkTarget, linkTarget) 400 } 401 402 // Good, now remove that copied link for the next test. 403 os.Remove(expectedPath) 404 405 // This copy command should resolve the symlink (note the trailing 406 // separator), copying the target into the test volume directory in the 407 // container. 408 dockerCmd(c, "cp", localLink+"/", cleanedContainerID+":/testVol") 409 410 // It *should not* have copied the directory using the target's name, but 411 // used the given name instead. 412 unexpectedPath := filepath.Join(testVol, cpTestPathParent) 413 if stat, err := os.Lstat(unexpectedPath); err == nil { 414 c.Fatalf("target name was copied: %q - %q", stat.Mode(), stat.Name()) 415 } 416 417 // It *should* have copied the directory using the asked name "dir_link". 418 stat, err := os.Lstat(expectedPath) 419 if err != nil { 420 c.Fatalf("unable to stat resource at %q: %v", expectedPath, err) 421 } 422 423 if !stat.IsDir() { 424 c.Errorf("should have copied a directory but got %q instead", stat.Mode()) 425 } 426 427 // And this directory should contain the file copied from the host at the 428 // expected location: "/testVol/dir_link/path/test" 429 expectedFilepath := filepath.Join(testVol, "dir_link/path/test") 430 fileContents, err := ioutil.ReadFile(expectedFilepath) 431 if err != nil { 432 c.Fatal(err) 433 } 434 435 if string(fileContents) != cpHostContents { 436 c.Fatalf("file contains %q but expected %q", string(fileContents), cpHostContents) 437 } 438 } 439 440 // Test for #5619 441 // Check that symlinks which are part of the resource path are still relative to the container's rootfs 442 func (s *DockerSuite) TestCpSymlinkComponent(c *check.C) { 443 testRequires(c, DaemonIsLinux) 444 out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpTestPath+" container_path") 445 if exitCode != 0 { 446 c.Fatal("failed to create a container", out) 447 } 448 449 cleanedContainerID := strings.TrimSpace(out) 450 451 out, _ = dockerCmd(c, "wait", cleanedContainerID) 452 if strings.TrimSpace(out) != "0" { 453 c.Fatal("failed to set up container", out) 454 } 455 456 if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil { 457 c.Fatal(err) 458 } 459 460 hostFile, err := os.Create(cpFullPath) 461 if err != nil { 462 c.Fatal(err) 463 } 464 defer hostFile.Close() 465 defer os.RemoveAll(cpTestPathParent) 466 467 fmt.Fprintf(hostFile, "%s", cpHostContents) 468 469 tmpdir, err := ioutil.TempDir("", "docker-integration") 470 471 if err != nil { 472 c.Fatal(err) 473 } 474 475 tmpname := filepath.Join(tmpdir, cpTestName) 476 defer os.RemoveAll(tmpdir) 477 478 path := path.Join("/", "container_path", cpTestName) 479 480 dockerCmd(c, "cp", cleanedContainerID+":"+path, tmpdir) 481 482 file, _ := os.Open(tmpname) 483 defer file.Close() 484 485 test, err := ioutil.ReadAll(file) 486 if err != nil { 487 c.Fatal(err) 488 } 489 490 if string(test) == cpHostContents { 491 c.Errorf("output matched host file -- symlink path component can escape container rootfs") 492 } 493 494 if string(test) != cpContainerContents { 495 c.Errorf("output doesn't match the input for symlink path component") 496 } 497 498 } 499 500 // Check that cp with unprivileged user doesn't return any error 501 func (s *DockerSuite) TestCpUnprivilegedUser(c *check.C) { 502 testRequires(c, DaemonIsLinux) 503 testRequires(c, UnixCli) // uses chmod/su: not available on windows 504 505 out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "touch "+cpTestName) 506 if exitCode != 0 { 507 c.Fatal("failed to create a container", out) 508 } 509 510 cleanedContainerID := strings.TrimSpace(out) 511 512 out, _ = dockerCmd(c, "wait", cleanedContainerID) 513 if strings.TrimSpace(out) != "0" { 514 c.Fatal("failed to set up container", out) 515 } 516 517 tmpdir, err := ioutil.TempDir("", "docker-integration") 518 if err != nil { 519 c.Fatal(err) 520 } 521 522 defer os.RemoveAll(tmpdir) 523 524 if err = os.Chmod(tmpdir, 0777); err != nil { 525 c.Fatal(err) 526 } 527 528 path := cpTestName 529 530 _, _, err = runCommandWithOutput(exec.Command("su", "unprivilegeduser", "-c", dockerBinary+" cp "+cleanedContainerID+":"+path+" "+tmpdir)) 531 if err != nil { 532 c.Fatalf("couldn't copy with unprivileged user: %s:%s %s", cleanedContainerID, path, err) 533 } 534 535 } 536 537 func (s *DockerSuite) TestCpSpecialFiles(c *check.C) { 538 testRequires(c, DaemonIsLinux) 539 testRequires(c, SameHostDaemon) 540 541 outDir, err := ioutil.TempDir("", "cp-test-special-files") 542 if err != nil { 543 c.Fatal(err) 544 } 545 defer os.RemoveAll(outDir) 546 547 out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "touch /foo") 548 if exitCode != 0 { 549 c.Fatal("failed to create a container", out) 550 } 551 552 cleanedContainerID := strings.TrimSpace(out) 553 554 out, _ = dockerCmd(c, "wait", cleanedContainerID) 555 if strings.TrimSpace(out) != "0" { 556 c.Fatal("failed to set up container", out) 557 } 558 559 // Copy actual /etc/resolv.conf 560 dockerCmd(c, "cp", cleanedContainerID+":/etc/resolv.conf", outDir) 561 562 expected, err := readContainerFile(cleanedContainerID, "resolv.conf") 563 actual, err := ioutil.ReadFile(outDir + "/resolv.conf") 564 565 if !bytes.Equal(actual, expected) { 566 c.Fatalf("Expected copied file to be duplicate of the container resolvconf") 567 } 568 569 // Copy actual /etc/hosts 570 dockerCmd(c, "cp", cleanedContainerID+":/etc/hosts", outDir) 571 572 expected, err = readContainerFile(cleanedContainerID, "hosts") 573 actual, err = ioutil.ReadFile(outDir + "/hosts") 574 575 if !bytes.Equal(actual, expected) { 576 c.Fatalf("Expected copied file to be duplicate of the container hosts") 577 } 578 579 // Copy actual /etc/resolv.conf 580 dockerCmd(c, "cp", cleanedContainerID+":/etc/hostname", outDir) 581 582 expected, err = readContainerFile(cleanedContainerID, "hostname") 583 actual, err = ioutil.ReadFile(outDir + "/hostname") 584 585 if !bytes.Equal(actual, expected) { 586 c.Fatalf("Expected copied file to be duplicate of the container resolvconf") 587 } 588 589 } 590 591 func (s *DockerSuite) TestCpVolumePath(c *check.C) { 592 // stat /tmp/cp-test-volumepath851508420/test gets permission denied for the user 593 testRequires(c, NotUserNamespace) 594 testRequires(c, DaemonIsLinux) 595 testRequires(c, SameHostDaemon) 596 597 tmpDir, err := ioutil.TempDir("", "cp-test-volumepath") 598 if err != nil { 599 c.Fatal(err) 600 } 601 defer os.RemoveAll(tmpDir) 602 outDir, err := ioutil.TempDir("", "cp-test-volumepath-out") 603 if err != nil { 604 c.Fatal(err) 605 } 606 defer os.RemoveAll(outDir) 607 _, err = os.Create(tmpDir + "/test") 608 if err != nil { 609 c.Fatal(err) 610 } 611 612 out, exitCode := dockerCmd(c, "run", "-d", "-v", "/foo", "-v", tmpDir+"/test:/test", "-v", tmpDir+":/baz", "busybox", "/bin/sh", "-c", "touch /foo/bar") 613 if exitCode != 0 { 614 c.Fatal("failed to create a container", out) 615 } 616 617 cleanedContainerID := strings.TrimSpace(out) 618 619 out, _ = dockerCmd(c, "wait", cleanedContainerID) 620 if strings.TrimSpace(out) != "0" { 621 c.Fatal("failed to set up container", out) 622 } 623 624 // Copy actual volume path 625 dockerCmd(c, "cp", cleanedContainerID+":/foo", outDir) 626 627 stat, err := os.Stat(outDir + "/foo") 628 if err != nil { 629 c.Fatal(err) 630 } 631 if !stat.IsDir() { 632 c.Fatal("expected copied content to be dir") 633 } 634 stat, err = os.Stat(outDir + "/foo/bar") 635 if err != nil { 636 c.Fatal(err) 637 } 638 if stat.IsDir() { 639 c.Fatal("Expected file `bar` to be a file") 640 } 641 642 // Copy file nested in volume 643 dockerCmd(c, "cp", cleanedContainerID+":/foo/bar", outDir) 644 645 stat, err = os.Stat(outDir + "/bar") 646 if err != nil { 647 c.Fatal(err) 648 } 649 if stat.IsDir() { 650 c.Fatal("Expected file `bar` to be a file") 651 } 652 653 // Copy Bind-mounted dir 654 dockerCmd(c, "cp", cleanedContainerID+":/baz", outDir) 655 stat, err = os.Stat(outDir + "/baz") 656 if err != nil { 657 c.Fatal(err) 658 } 659 if !stat.IsDir() { 660 c.Fatal("Expected `baz` to be a dir") 661 } 662 663 // Copy file nested in bind-mounted dir 664 dockerCmd(c, "cp", cleanedContainerID+":/baz/test", outDir) 665 fb, err := ioutil.ReadFile(outDir + "/baz/test") 666 if err != nil { 667 c.Fatal(err) 668 } 669 fb2, err := ioutil.ReadFile(tmpDir + "/test") 670 if err != nil { 671 c.Fatal(err) 672 } 673 if !bytes.Equal(fb, fb2) { 674 c.Fatalf("Expected copied file to be duplicate of bind-mounted file") 675 } 676 677 // Copy bind-mounted file 678 dockerCmd(c, "cp", cleanedContainerID+":/test", outDir) 679 fb, err = ioutil.ReadFile(outDir + "/test") 680 if err != nil { 681 c.Fatal(err) 682 } 683 fb2, err = ioutil.ReadFile(tmpDir + "/test") 684 if err != nil { 685 c.Fatal(err) 686 } 687 if !bytes.Equal(fb, fb2) { 688 c.Fatalf("Expected copied file to be duplicate of bind-mounted file") 689 } 690 691 } 692 693 func (s *DockerSuite) TestCpToDot(c *check.C) { 694 testRequires(c, DaemonIsLinux) 695 out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /test") 696 if exitCode != 0 { 697 c.Fatal("failed to create a container", out) 698 } 699 700 cleanedContainerID := strings.TrimSpace(out) 701 702 out, _ = dockerCmd(c, "wait", cleanedContainerID) 703 if strings.TrimSpace(out) != "0" { 704 c.Fatal("failed to set up container", out) 705 } 706 707 tmpdir, err := ioutil.TempDir("", "docker-integration") 708 if err != nil { 709 c.Fatal(err) 710 } 711 defer os.RemoveAll(tmpdir) 712 cwd, err := os.Getwd() 713 if err != nil { 714 c.Fatal(err) 715 } 716 defer os.Chdir(cwd) 717 if err := os.Chdir(tmpdir); err != nil { 718 c.Fatal(err) 719 } 720 dockerCmd(c, "cp", cleanedContainerID+":/test", ".") 721 content, err := ioutil.ReadFile("./test") 722 if string(content) != "lololol\n" { 723 c.Fatalf("Wrong content in copied file %q, should be %q", content, "lololol\n") 724 } 725 } 726 727 func (s *DockerSuite) TestCpToStdout(c *check.C) { 728 testRequires(c, DaemonIsLinux) 729 out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /test") 730 if exitCode != 0 { 731 c.Fatalf("failed to create a container:%s\n", out) 732 } 733 734 cID := strings.TrimSpace(out) 735 736 out, _ = dockerCmd(c, "wait", cID) 737 if strings.TrimSpace(out) != "0" { 738 c.Fatalf("failed to set up container:%s\n", out) 739 } 740 741 out, _, err := runCommandPipelineWithOutput( 742 exec.Command(dockerBinary, "cp", cID+":/test", "-"), 743 exec.Command("tar", "-vtf", "-")) 744 745 if err != nil { 746 c.Fatalf("Failed to run commands: %s", err) 747 } 748 749 if !strings.Contains(out, "test") || !strings.Contains(out, "-rw") { 750 c.Fatalf("Missing file from tar TOC:\n%s", out) 751 } 752 } 753 754 func (s *DockerSuite) TestCpNameHasColon(c *check.C) { 755 testRequires(c, SameHostDaemon) 756 757 out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /te:s:t") 758 if exitCode != 0 { 759 c.Fatal("failed to create a container", out) 760 } 761 762 cleanedContainerID := strings.TrimSpace(out) 763 764 out, _ = dockerCmd(c, "wait", cleanedContainerID) 765 if strings.TrimSpace(out) != "0" { 766 c.Fatal("failed to set up container", out) 767 } 768 769 tmpdir, err := ioutil.TempDir("", "docker-integration") 770 if err != nil { 771 c.Fatal(err) 772 } 773 defer os.RemoveAll(tmpdir) 774 dockerCmd(c, "cp", cleanedContainerID+":/te:s:t", tmpdir) 775 content, err := ioutil.ReadFile(tmpdir + "/te:s:t") 776 if string(content) != "lololol\n" { 777 c.Fatalf("Wrong content in copied file %q, should be %q", content, "lololol\n") 778 } 779 } 780 781 func (s *DockerSuite) TestCopyAndRestart(c *check.C) { 782 testRequires(c, DaemonIsLinux) 783 expectedMsg := "hello" 784 out, _ := dockerCmd(c, "run", "-d", "busybox", "echo", expectedMsg) 785 id := strings.TrimSpace(string(out)) 786 787 out, _ = dockerCmd(c, "wait", id) 788 789 status := strings.TrimSpace(out) 790 if status != "0" { 791 c.Fatalf("container exited with status %s", status) 792 } 793 794 tmpDir, err := ioutil.TempDir("", "test-docker-restart-after-copy-") 795 if err != nil { 796 c.Fatalf("unable to make temporary directory: %s", err) 797 } 798 defer os.RemoveAll(tmpDir) 799 800 dockerCmd(c, "cp", fmt.Sprintf("%s:/etc/issue", id), tmpDir) 801 802 out, _ = dockerCmd(c, "start", "-a", id) 803 804 msg := strings.TrimSpace(out) 805 if msg != expectedMsg { 806 c.Fatalf("expected %q but got %q", expectedMsg, msg) 807 } 808 } 809 810 func (s *DockerSuite) TestCopyCreatedContainer(c *check.C) { 811 testRequires(c, DaemonIsLinux) 812 dockerCmd(c, "create", "--name", "test_cp", "-v", "/test", "busybox") 813 814 tmpDir, err := ioutil.TempDir("", "test") 815 if err != nil { 816 c.Fatalf("unable to make temporary directory: %s", err) 817 } 818 defer os.RemoveAll(tmpDir) 819 dockerCmd(c, "cp", "test_cp:/bin/sh", tmpDir) 820 }