1 /* 2 * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* @test 25 * @bug 4313887 6838333 6917021 7006126 6950237 8006645 8201407 26 * @summary Unit test for java.nio.file.Files copy and move methods (use -Dseed=X to set PRNG seed) 27 * @library .. /test/lib 28 * @build jdk.test.lib.Platform jdk.test.lib.RandomFactory 29 * CopyAndMove PassThroughFileSystem 30 * @run main/othervm CopyAndMove 31 * @key randomness 32 */ 33 34 import java.io.*; 35 import java.nio.ByteBuffer; 36 import java.nio.file.*; 37 import static java.nio.file.Files.*; 38 import static java.nio.file.StandardCopyOption.*; 39 import static java.nio.file.LinkOption.*; 40 import java.nio.file.attribute.*; 41 import java.util.*; 42 import java.util.concurrent.TimeUnit; 43 import jdk.test.lib.Platform; 44 import jdk.test.lib.RandomFactory; 45 46 public class CopyAndMove { 47 static final Random rand = RandomFactory.getRandom(); heads()48 static boolean heads() { return rand.nextBoolean(); } 49 private static boolean testPosixAttributes = false; 50 main(String[] args)51 public static void main(String[] args) throws Exception { 52 Path dir1 = TestUtil.createTemporaryDirectory(); 53 try { 54 55 // Same directory 56 FileStore fileStore1 = getFileStore(dir1); 57 printDirInfo("dir1", dir1, fileStore1); 58 testPosixAttributes = fileStore1.supportsFileAttributeView("posix"); 59 testCopyFileToFile(dir1, dir1, TestUtil.supportsLinks(dir1)); 60 testMove(dir1, dir1, TestUtil.supportsLinks(dir1)); 61 62 // Different directories. Use test.dir if possible as it might be 63 // a different volume/file system and so improve test coverage. 64 String testDir = System.getProperty("test.dir", "."); 65 Path dir2 = TestUtil.createTemporaryDirectory(testDir); 66 try { 67 boolean testSymbolicLinks = 68 TestUtil.supportsLinks(dir1) && TestUtil.supportsLinks(dir2); 69 FileStore fileStore2 = getFileStore(dir2); 70 printDirInfo("dir2", dir2, fileStore2); 71 testPosixAttributes = fileStore1.supportsFileAttributeView("posix") && 72 fileStore2.supportsFileAttributeView("posix"); 73 testCopyFileToFile(dir1, dir2, testSymbolicLinks); 74 testMove(dir1, dir2, testSymbolicLinks); 75 } finally { 76 TestUtil.removeAll(dir2); 77 } 78 79 // Target is location associated with custom provider 80 Path dir3 = PassThroughFileSystem.create().getPath(dir1.toString()); 81 FileStore fileStore3 = getFileStore(dir3); 82 printDirInfo("dir3", dir3, fileStore3); 83 testPosixAttributes = fileStore1.supportsFileAttributeView("posix") && 84 fileStore3.supportsFileAttributeView("posix"); 85 testCopyFileToFile(dir1, dir3, false); 86 testMove(dir1, dir3, false); 87 88 // Test copy(InputStream,Path) and copy(Path,OutputStream) 89 testCopyInputStreamToFile(); 90 testCopyFileToOuputStream(); 91 92 } finally { 93 TestUtil.removeAll(dir1); 94 } 95 } 96 printDirInfo(String name, Path dir, FileStore store)97 static void printDirInfo(String name, Path dir, FileStore store) 98 throws IOException { 99 System.err.format("%s: %s (%s)%n", name, dir, store.type()); 100 } 101 checkBasicAttributes(BasicFileAttributes attrs1, BasicFileAttributes attrs2)102 static void checkBasicAttributes(BasicFileAttributes attrs1, 103 BasicFileAttributes attrs2) 104 { 105 // check file type 106 assertTrue(attrs1.isRegularFile() == attrs2.isRegularFile()); 107 assertTrue(attrs1.isDirectory() == attrs2.isDirectory()); 108 assertTrue(attrs1.isSymbolicLink() == attrs2.isSymbolicLink()); 109 assertTrue(attrs1.isOther() == attrs2.isOther()); 110 111 // check last modified time if not a symbolic link 112 if (!attrs1.isSymbolicLink()) { 113 long time1 = attrs1.lastModifiedTime().to(TimeUnit.SECONDS); 114 long time2 = attrs2.lastModifiedTime().to(TimeUnit.SECONDS); 115 116 if (time1 != time2) { 117 System.err.format("File time for %s is %s\n", attrs1.fileKey(), attrs1.lastModifiedTime()); 118 System.err.format("File time for %s is %s\n", attrs2.fileKey(), attrs2.lastModifiedTime()); 119 assertTrue(false); 120 } 121 } 122 123 // check size 124 if (attrs1.isRegularFile()) 125 assertTrue(attrs1.size() == attrs2.size()); 126 } 127 checkPosixAttributes(PosixFileAttributes attrs1, PosixFileAttributes attrs2)128 static void checkPosixAttributes(PosixFileAttributes attrs1, 129 PosixFileAttributes attrs2) 130 { 131 assertTrue(attrs1.permissions().equals(attrs2.permissions()), 132 "permissions%n1 (%d): %s%n2 (%d): %s%n%n", 133 attrs1.permissions().size(), attrs1.permissions(), 134 attrs2.permissions().size(), attrs2.permissions()); 135 assertTrue(attrs1.owner().equals(attrs2.owner()), 136 "owner%n1: %s%n2: %s%n%n", attrs1.owner(), attrs2.owner()); 137 assertTrue(attrs1.group().equals(attrs2.group()), 138 "group%n1: %s%n2: %s%n%n", attrs1.group(), attrs2.group()); 139 } 140 checkDosAttributes(DosFileAttributes attrs1, DosFileAttributes attrs2)141 static void checkDosAttributes(DosFileAttributes attrs1, 142 DosFileAttributes attrs2) 143 { 144 assertTrue(attrs1.isReadOnly() == attrs2.isReadOnly(), 145 "isReadOnly%n1: %s%n2: %s%n%n", attrs1.isReadOnly(), attrs2.isReadOnly()); 146 assertTrue(attrs1.isHidden() == attrs2.isHidden(), 147 "isHidden%n1: %s%n2: %s%n%n", attrs1.isHidden(), attrs2.isHidden()); 148 assertTrue(attrs1.isSystem() == attrs2.isSystem(), 149 "isSystem%n1: %s%n2: %s%n%n", attrs1.isSystem(), attrs2.isSystem()); 150 } 151 checkUserDefinedFileAttributes(Map<String,ByteBuffer> attrs1, Map<String,ByteBuffer> attrs2)152 static void checkUserDefinedFileAttributes(Map<String,ByteBuffer> attrs1, 153 Map<String,ByteBuffer> attrs2) 154 { 155 assert attrs1.size() == attrs2.size(); 156 for (String name: attrs1.keySet()) { 157 ByteBuffer bb1 = attrs1.get(name); 158 ByteBuffer bb2 = attrs2.get(name); 159 assertTrue(bb2 != null); 160 assertTrue(bb1.equals(bb2)); 161 } 162 } 163 readUserDefinedFileAttributes(Path file)164 static Map<String,ByteBuffer> readUserDefinedFileAttributes(Path file) 165 throws IOException 166 { 167 UserDefinedFileAttributeView view = 168 getFileAttributeView(file, UserDefinedFileAttributeView.class); 169 Map<String,ByteBuffer> result = new HashMap<>(); 170 for (String name: view.list()) { 171 int size = view.size(name); 172 ByteBuffer bb = ByteBuffer.allocate(size); 173 int n = view.read(name, bb); 174 assertTrue(n == size); 175 bb.flip(); 176 result.put(name, bb); 177 } 178 return result; 179 } 180 181 // move source to target with verification moveAndVerify(Path source, Path target, CopyOption... options)182 static void moveAndVerify(Path source, Path target, CopyOption... options) 183 throws IOException 184 { 185 // read attributes before file is moved 186 BasicFileAttributes basicAttributes = null; 187 PosixFileAttributes posixAttributes = null; 188 DosFileAttributes dosAttributes = null; 189 Map<String,ByteBuffer> namedAttributes = null; 190 191 // get file attributes of source file 192 if (Platform.isWindows()) { 193 dosAttributes = readAttributes(source, DosFileAttributes.class, NOFOLLOW_LINKS); 194 basicAttributes = dosAttributes; 195 } else { 196 posixAttributes = readAttributes(source, PosixFileAttributes.class, NOFOLLOW_LINKS); 197 basicAttributes = posixAttributes; 198 } 199 if (basicAttributes == null) 200 basicAttributes = readAttributes(source, BasicFileAttributes.class, NOFOLLOW_LINKS); 201 202 // hash file contents if regular file 203 int hash = (basicAttributes.isRegularFile()) ? computeHash(source) : 0; 204 205 // record link target if symbolic link 206 Path linkTarget = null; 207 if (basicAttributes.isSymbolicLink()) 208 linkTarget = readSymbolicLink(source); 209 210 // read named attributes if available (and file is not a sym link) 211 if (!basicAttributes.isSymbolicLink() && 212 getFileStore(source).supportsFileAttributeView("xattr")) 213 { 214 namedAttributes = readUserDefinedFileAttributes(source); 215 } 216 217 // move file 218 Path result = move(source, target, options); 219 assertTrue(result == target); 220 221 // verify source does not exist 222 assertTrue(notExists(source)); 223 224 // verify file contents 225 if (basicAttributes.isRegularFile()) { 226 if (computeHash(target) != hash) 227 throw new RuntimeException("Failed to verify move of regular file"); 228 } 229 230 // verify link target 231 if (basicAttributes.isSymbolicLink()) { 232 if (!readSymbolicLink(target).equals(linkTarget)) 233 throw new RuntimeException("Failed to verify move of symbolic link"); 234 } 235 236 // verify basic attributes 237 checkBasicAttributes(basicAttributes, 238 readAttributes(target, BasicFileAttributes.class, NOFOLLOW_LINKS)); 239 240 // verify other attributes when same provider 241 if (source.getFileSystem().provider() == target.getFileSystem().provider()) { 242 243 // verify POSIX attributes 244 if (posixAttributes != null && 245 !basicAttributes.isSymbolicLink() && 246 testPosixAttributes) 247 { 248 checkPosixAttributes(posixAttributes, 249 readAttributes(target, PosixFileAttributes.class, NOFOLLOW_LINKS)); 250 } 251 252 // verify DOS attributes 253 if (dosAttributes != null && !basicAttributes.isSymbolicLink()) { 254 DosFileAttributes attrs = 255 readAttributes(target, DosFileAttributes.class, NOFOLLOW_LINKS); 256 checkDosAttributes(dosAttributes, attrs); 257 } 258 259 // verify named attributes 260 if (namedAttributes != null && 261 getFileStore(target).supportsFileAttributeView("xattr")) 262 { 263 checkUserDefinedFileAttributes(namedAttributes, 264 readUserDefinedFileAttributes(target)); 265 } 266 } 267 } 268 269 /** 270 * Tests all possible ways to invoke move 271 */ testMove(Path dir1, Path dir2, boolean supportsLinks)272 static void testMove(Path dir1, Path dir2, boolean supportsLinks) 273 throws IOException 274 { 275 Path source, target, entry; 276 277 boolean sameDevice = getFileStore(dir1).equals(getFileStore(dir2)); 278 279 // -- regular file -- 280 281 /** 282 * Test: move regular file, target does not exist 283 */ 284 source = createSourceFile(dir1); 285 target = getTargetFile(dir2); 286 moveAndVerify(source, target); 287 delete(target); 288 289 /** 290 * Test: move regular file, target exists 291 */ 292 source = createSourceFile(dir1); 293 target = getTargetFile(dir2); 294 createFile(target); 295 try { 296 moveAndVerify(source, target); 297 throw new RuntimeException("FileAlreadyExistsException expected"); 298 } catch (FileAlreadyExistsException x) { 299 } 300 delete(target); 301 createDirectory(target); 302 try { 303 moveAndVerify(source, target); 304 throw new RuntimeException("FileAlreadyExistsException expected"); 305 } catch (FileAlreadyExistsException x) { 306 } 307 delete(source); 308 delete(target); 309 310 /** 311 * Test: move regular file, target does not exist 312 */ 313 source = createSourceFile(dir1); 314 target = getTargetFile(dir2); 315 moveAndVerify(source, target, REPLACE_EXISTING); 316 delete(target); 317 318 /** 319 * Test: move regular file, target exists 320 */ 321 source = createSourceFile(dir1); 322 target = getTargetFile(dir2); 323 createFile(target); 324 moveAndVerify(source, target, REPLACE_EXISTING); 325 delete(target); 326 327 /** 328 * Test: move regular file, target exists and is empty directory 329 */ 330 source = createSourceFile(dir1); 331 target = getTargetFile(dir2); 332 createDirectory(target); 333 moveAndVerify(source, target, REPLACE_EXISTING); 334 delete(target); 335 336 /** 337 * Test: move regular file, target exists and is non-empty directory 338 */ 339 source = createSourceFile(dir1); 340 target = getTargetFile(dir2); 341 createDirectory(target); 342 entry = target.resolve("foo"); 343 createFile(entry); 344 try { 345 moveAndVerify(source, target); 346 throw new RuntimeException("FileAlreadyExistsException expected"); 347 } catch (FileAlreadyExistsException x) { 348 } 349 delete(entry); 350 delete(source); 351 delete(target); 352 353 /** 354 * Test atomic move of regular file (same file store) 355 */ 356 source = createSourceFile(dir1); 357 target = getTargetFile(dir1); 358 moveAndVerify(source, target, ATOMIC_MOVE); 359 delete(target); 360 361 /** 362 * Test atomic move of regular file (different file store) 363 */ 364 if (!sameDevice) { 365 source = createSourceFile(dir1); 366 target = getTargetFile(dir2); 367 try { 368 moveAndVerify(source, target, ATOMIC_MOVE); 369 throw new RuntimeException("AtomicMoveNotSupportedException expected"); 370 } catch (AtomicMoveNotSupportedException x) { 371 } 372 delete(source); 373 } 374 375 // -- directories -- 376 377 /* 378 * Test: move empty directory, target does not exist 379 */ 380 source = createSourceDirectory(dir1); 381 target = getTargetFile(dir2); 382 moveAndVerify(source, target); 383 delete(target); 384 385 /** 386 * Test: move empty directory, target exists 387 */ 388 source = createSourceDirectory(dir1); 389 target = getTargetFile(dir2); 390 createFile(target); 391 try { 392 moveAndVerify(source, target); 393 throw new RuntimeException("FileAlreadyExistsException expected"); 394 } catch (FileAlreadyExistsException x) { 395 } 396 delete(target); 397 createDirectory(target); 398 try { 399 moveAndVerify(source, target); 400 throw new RuntimeException("FileAlreadyExistsException expected"); 401 } catch (FileAlreadyExistsException x) { 402 } 403 delete(source); 404 delete(target); 405 406 /** 407 * Test: move empty directory, target does not exist 408 */ 409 source = createSourceDirectory(dir1); 410 target = getTargetFile(dir2); 411 moveAndVerify(source, target, REPLACE_EXISTING); 412 delete(target); 413 414 /** 415 * Test: move empty directory, target exists 416 */ 417 source = createSourceDirectory(dir1); 418 target = getTargetFile(dir2); 419 createFile(target); 420 moveAndVerify(source, target, REPLACE_EXISTING); 421 delete(target); 422 423 /** 424 * Test: move empty, target exists and is empty directory 425 */ 426 source = createSourceDirectory(dir1); 427 target = getTargetFile(dir2); 428 createDirectory(target); 429 moveAndVerify(source, target, REPLACE_EXISTING); 430 delete(target); 431 432 /** 433 * Test: move empty directory, target exists and is non-empty directory 434 */ 435 source = createSourceDirectory(dir1); 436 target = getTargetFile(dir2); 437 createDirectory(target); 438 entry = target.resolve("foo"); 439 createFile(entry); 440 try { 441 moveAndVerify(source, target, REPLACE_EXISTING); 442 throw new RuntimeException("DirectoryNotEmptyException expected"); 443 } catch (DirectoryNotEmptyException x) { 444 } 445 delete(entry); 446 delete(source); 447 delete(target); 448 449 /** 450 * Test: move non-empty directory (same file system) 451 */ 452 source = createSourceDirectory(dir1); 453 createFile(source.resolve("foo")); 454 target = getTargetFile(dir1); 455 moveAndVerify(source, target); 456 delete(target.resolve("foo")); 457 delete(target); 458 459 /** 460 * Test: move non-empty directory (different file store) 461 */ 462 if (!sameDevice) { 463 source = createSourceDirectory(dir1); 464 createFile(source.resolve("foo")); 465 target = getTargetFile(dir2); 466 try { 467 moveAndVerify(source, target); 468 throw new RuntimeException("IOException expected"); 469 } catch (IOException x) { 470 if (!(x instanceof DirectoryNotEmptyException)) { 471 throw new RuntimeException 472 ("DirectoryNotEmptyException expected", x); 473 } 474 } 475 delete(source.resolve("foo")); 476 delete(source); 477 } 478 479 /** 480 * Test atomic move of directory (same file store) 481 */ 482 source = createSourceDirectory(dir1); 483 createFile(source.resolve("foo")); 484 target = getTargetFile(dir1); 485 moveAndVerify(source, target, ATOMIC_MOVE); 486 delete(target.resolve("foo")); 487 delete(target); 488 489 // -- symbolic links -- 490 491 /** 492 * Test: Move symbolic link to file, target does not exist 493 */ 494 if (supportsLinks) { 495 Path tmp = createSourceFile(dir1); 496 source = dir1.resolve("link"); 497 createSymbolicLink(source, tmp); 498 target = getTargetFile(dir2); 499 moveAndVerify(source, target); 500 delete(target); 501 delete(tmp); 502 } 503 504 /** 505 * Test: Move symbolic link to directory, target does not exist 506 */ 507 if (supportsLinks) { 508 source = dir1.resolve("link"); 509 createSymbolicLink(source, dir2); 510 target = getTargetFile(dir2); 511 moveAndVerify(source, target); 512 delete(target); 513 } 514 515 /** 516 * Test: Move broken symbolic link, target does not exists 517 */ 518 if (supportsLinks) { 519 Path tmp = Paths.get("doesnotexist"); 520 source = dir1.resolve("link"); 521 createSymbolicLink(source, tmp); 522 target = getTargetFile(dir2); 523 moveAndVerify(source, target); 524 delete(target); 525 } 526 527 /** 528 * Test: Move symbolic link, target exists 529 */ 530 if (supportsLinks) { 531 source = dir1.resolve("link"); 532 createSymbolicLink(source, dir2); 533 target = getTargetFile(dir2); 534 createFile(target); 535 try { 536 moveAndVerify(source, target); 537 throw new RuntimeException("FileAlreadyExistsException expected"); 538 } catch (FileAlreadyExistsException x) { 539 } 540 delete(source); 541 delete(target); 542 } 543 544 /** 545 * Test: Move regular file, target exists 546 */ 547 if (supportsLinks) { 548 source = dir1.resolve("link"); 549 createSymbolicLink(source, dir2); 550 target = getTargetFile(dir2); 551 createFile(target); 552 moveAndVerify(source, target, REPLACE_EXISTING); 553 delete(target); 554 } 555 556 /** 557 * Test: move symbolic link, target exists and is empty directory 558 */ 559 if (supportsLinks) { 560 source = dir1.resolve("link"); 561 createSymbolicLink(source, dir2); 562 target = getTargetFile(dir2); 563 createDirectory(target); 564 moveAndVerify(source, target, REPLACE_EXISTING); 565 delete(target); 566 } 567 568 /** 569 * Test: symbolic link, target exists and is non-empty directory 570 */ 571 if (supportsLinks) { 572 source = dir1.resolve("link"); 573 createSymbolicLink(source, dir2); 574 target = getTargetFile(dir2); 575 createDirectory(target); 576 entry = target.resolve("foo"); 577 createFile(entry); 578 try { 579 moveAndVerify(source, target); 580 throw new RuntimeException("FileAlreadyExistsException expected"); 581 } catch (FileAlreadyExistsException x) { 582 } 583 delete(entry); 584 delete(source); 585 delete(target); 586 } 587 588 /** 589 * Test atomic move of symbolic link (same file store) 590 */ 591 if (supportsLinks) { 592 source = dir1.resolve("link"); 593 createSymbolicLink(source, dir1); 594 target = getTargetFile(dir2); 595 createFile(target); 596 moveAndVerify(source, target, REPLACE_EXISTING); 597 delete(target); 598 } 599 600 // -- misc. tests -- 601 602 /** 603 * Test nulls 604 */ 605 source = createSourceFile(dir1); 606 target = getTargetFile(dir2); 607 try { 608 move(null, target); 609 throw new RuntimeException("NullPointerException expected"); 610 } catch (NullPointerException x) { } 611 try { 612 move(source, null); 613 throw new RuntimeException("NullPointerException expected"); 614 } catch (NullPointerException x) { } 615 try { 616 move(source, target, (CopyOption[])null); 617 throw new RuntimeException("NullPointerException expected"); 618 } catch (NullPointerException x) { } 619 try { 620 CopyOption[] opts = { REPLACE_EXISTING, null }; 621 move(source, target, opts); 622 throw new RuntimeException("NullPointerException expected"); 623 } catch (NullPointerException x) { } 624 delete(source); 625 626 /** 627 * Test UOE 628 */ 629 source = createSourceFile(dir1); 630 target = getTargetFile(dir2); 631 try { 632 move(source, target, new CopyOption() { }); 633 } catch (UnsupportedOperationException x) { } 634 try { 635 move(source, target, REPLACE_EXISTING, new CopyOption() { }); 636 } catch (UnsupportedOperationException x) { } 637 delete(source); 638 } 639 640 // copy source to target with verification copyAndVerify(Path source, Path target, CopyOption... options)641 static void copyAndVerify(Path source, Path target, CopyOption... options) 642 throws IOException 643 { 644 Path result = copy(source, target, options); 645 assertTrue(result == target); 646 647 // get attributes of source and target file to verify copy 648 boolean followLinks = true; 649 LinkOption[] linkOptions = new LinkOption[0]; 650 boolean copyAttributes = false; 651 for (CopyOption opt : options) { 652 if (opt == NOFOLLOW_LINKS) { 653 followLinks = false; 654 linkOptions = new LinkOption[] { NOFOLLOW_LINKS }; 655 } 656 if (opt == COPY_ATTRIBUTES) 657 copyAttributes = true; 658 } 659 BasicFileAttributes basicAttributes = 660 readAttributes(source, BasicFileAttributes.class, linkOptions); 661 662 // check hash if regular file 663 if (basicAttributes.isRegularFile()) 664 assertTrue(computeHash(source) == computeHash(target)); 665 666 // check link target if symbolic link 667 if (basicAttributes.isSymbolicLink()) 668 assert(readSymbolicLink(source).equals(readSymbolicLink(target))); 669 670 // check that attributes are copied 671 if (copyAttributes && followLinks) { 672 checkBasicAttributes(basicAttributes, 673 readAttributes(source, BasicFileAttributes.class, linkOptions)); 674 675 // verify other attributes when same provider 676 if (source.getFileSystem().provider() == target.getFileSystem().provider()) { 677 678 // check POSIX attributes are copied 679 if (!Platform.isWindows() && testPosixAttributes) { 680 checkPosixAttributes( 681 readAttributes(source, PosixFileAttributes.class, linkOptions), 682 readAttributes(target, PosixFileAttributes.class, linkOptions)); 683 } 684 685 // check DOS attributes are copied 686 if (Platform.isWindows()) { 687 checkDosAttributes( 688 readAttributes(source, DosFileAttributes.class, linkOptions), 689 readAttributes(target, DosFileAttributes.class, linkOptions)); 690 } 691 692 // check named attributes are copied 693 if (followLinks && 694 getFileStore(source).supportsFileAttributeView("xattr") && 695 getFileStore(target).supportsFileAttributeView("xattr")) 696 { 697 checkUserDefinedFileAttributes(readUserDefinedFileAttributes(source), 698 readUserDefinedFileAttributes(target)); 699 } 700 } 701 } 702 } 703 704 /** 705 * Tests all possible ways to invoke copy to copy a file to a file 706 */ testCopyFileToFile(Path dir1, Path dir2, boolean supportsLinks)707 static void testCopyFileToFile(Path dir1, Path dir2, boolean supportsLinks) 708 throws IOException 709 { 710 Path source, target, link, entry; 711 712 // -- regular file -- 713 714 /** 715 * Test: move regular file, target does not exist 716 */ 717 source = createSourceFile(dir1); 718 target = getTargetFile(dir2); 719 copyAndVerify(source, target); 720 delete(source); 721 delete(target); 722 723 /** 724 * Test: copy regular file, target exists 725 */ 726 source = createSourceFile(dir1); 727 target = getTargetFile(dir2); 728 createFile(target); 729 try { 730 copyAndVerify(source, target); 731 throw new RuntimeException("FileAlreadyExistsException expected"); 732 } catch (FileAlreadyExistsException x) { 733 } 734 delete(target); 735 createDirectory(target); 736 try { 737 copyAndVerify(source, target); 738 throw new RuntimeException("FileAlreadyExistsException expected"); 739 } catch (FileAlreadyExistsException x) { 740 } 741 delete(source); 742 delete(target); 743 744 /** 745 * Test: copy regular file, target does not exist 746 */ 747 source = createSourceFile(dir1); 748 target = getTargetFile(dir2); 749 copyAndVerify(source, target, REPLACE_EXISTING); 750 delete(source); 751 delete(target); 752 753 /** 754 * Test: copy regular file, target exists 755 */ 756 source = createSourceFile(dir1); 757 target = getTargetFile(dir2); 758 createFile(target); 759 copyAndVerify(source, target, REPLACE_EXISTING); 760 delete(source); 761 delete(target); 762 763 /** 764 * Test: copy regular file, target exists and is empty directory 765 */ 766 source = createSourceFile(dir1); 767 target = getTargetFile(dir2); 768 createDirectory(target); 769 copyAndVerify(source, target, REPLACE_EXISTING); 770 delete(source); 771 delete(target); 772 773 /** 774 * Test: copy regular file, target exists and is non-empty directory 775 */ 776 source = createSourceFile(dir1); 777 target = getTargetFile(dir2); 778 createDirectory(target); 779 entry = target.resolve("foo"); 780 createFile(entry); 781 try { 782 copyAndVerify(source, target); 783 throw new RuntimeException("FileAlreadyExistsException expected"); 784 } catch (FileAlreadyExistsException x) { 785 } 786 delete(entry); 787 delete(source); 788 delete(target); 789 790 /** 791 * Test: copy regular file + attributes 792 */ 793 source = createSourceFile(dir1); 794 target = getTargetFile(dir2); 795 copyAndVerify(source, target, COPY_ATTRIBUTES); 796 delete(source); 797 delete(target); 798 799 800 // -- directory -- 801 802 /* 803 * Test: copy directory, target does not exist 804 */ 805 source = createSourceDirectory(dir1); 806 target = getTargetFile(dir2); 807 copyAndVerify(source, target); 808 delete(source); 809 delete(target); 810 811 /** 812 * Test: copy directory, target exists 813 */ 814 source = createSourceDirectory(dir1); 815 target = getTargetFile(dir2); 816 createFile(target); 817 try { 818 copyAndVerify(source, target); 819 throw new RuntimeException("FileAlreadyExistsException expected"); 820 } catch (FileAlreadyExistsException x) { 821 } 822 delete(target); 823 createDirectory(target); 824 try { 825 copyAndVerify(source, target); 826 throw new RuntimeException("FileAlreadyExistsException expected"); 827 } catch (FileAlreadyExistsException x) { 828 } 829 delete(source); 830 delete(target); 831 832 /** 833 * Test: copy directory, target does not exist 834 */ 835 source = createSourceDirectory(dir1); 836 target = getTargetFile(dir2); 837 copyAndVerify(source, target, REPLACE_EXISTING); 838 delete(source); 839 delete(target); 840 841 /** 842 * Test: copy directory, target exists 843 */ 844 source = createSourceDirectory(dir1); 845 target = getTargetFile(dir2); 846 createFile(target); 847 copyAndVerify(source, target, REPLACE_EXISTING); 848 delete(source); 849 delete(target); 850 851 /** 852 * Test: copy directory, target exists and is empty directory 853 */ 854 source = createSourceDirectory(dir1); 855 target = getTargetFile(dir2); 856 createDirectory(target); 857 copyAndVerify(source, target, REPLACE_EXISTING); 858 delete(source); 859 delete(target); 860 861 /** 862 * Test: copy directory, target exists and is non-empty directory 863 */ 864 source = createSourceDirectory(dir1); 865 target = getTargetFile(dir2); 866 createDirectory(target); 867 entry = target.resolve("foo"); 868 createFile(entry); 869 try { 870 copyAndVerify(source, target, REPLACE_EXISTING); 871 throw new RuntimeException("DirectoryNotEmptyException expected"); 872 } catch (DirectoryNotEmptyException x) { 873 } 874 delete(entry); 875 delete(source); 876 delete(target); 877 878 /* 879 * Test: copy directory + attributes 880 */ 881 source = createSourceDirectory(dir1); 882 target = getTargetFile(dir2); 883 copyAndVerify(source, target, COPY_ATTRIBUTES); 884 delete(source); 885 delete(target); 886 887 // -- symbolic links -- 888 889 /** 890 * Test: Follow link 891 */ 892 if (supportsLinks) { 893 source = createSourceFile(dir1); 894 link = dir1.resolve("link"); 895 createSymbolicLink(link, source); 896 target = getTargetFile(dir2); 897 copyAndVerify(link, target); 898 delete(link); 899 delete(source); 900 } 901 902 /** 903 * Test: Copy link (to file) 904 */ 905 if (supportsLinks) { 906 source = createSourceFile(dir1); 907 link = dir1.resolve("link"); 908 createSymbolicLink(link, source); 909 target = getTargetFile(dir2); 910 copyAndVerify(link, target, NOFOLLOW_LINKS); 911 delete(link); 912 delete(source); 913 } 914 915 /** 916 * Test: Copy link (to directory) 917 */ 918 if (supportsLinks) { 919 source = dir1.resolve("mydir"); 920 createDirectory(source); 921 link = dir1.resolve("link"); 922 createSymbolicLink(link, source); 923 target = getTargetFile(dir2); 924 copyAndVerify(link, target, NOFOLLOW_LINKS); 925 delete(link); 926 delete(source); 927 } 928 929 /** 930 * Test: Copy broken link 931 */ 932 if (supportsLinks) { 933 assertTrue(notExists(source)); 934 link = dir1.resolve("link"); 935 createSymbolicLink(link, source); 936 target = getTargetFile(dir2); 937 copyAndVerify(link, target, NOFOLLOW_LINKS); 938 delete(link); 939 } 940 941 /** 942 * Test: Copy link to UNC (Windows only) 943 */ 944 if (supportsLinks && Platform.isWindows()) { 945 Path unc = Paths.get("\\\\rialto\\share\\file"); 946 link = dir1.resolve("link"); 947 createSymbolicLink(link, unc); 948 target = getTargetFile(dir2); 949 copyAndVerify(link, target, NOFOLLOW_LINKS); 950 delete(link); 951 } 952 953 // -- misc. tests -- 954 955 /** 956 * Test nulls 957 */ 958 source = createSourceFile(dir1); 959 target = getTargetFile(dir2); 960 try { 961 copy(source, null); 962 throw new RuntimeException("NullPointerException expected"); 963 } catch (NullPointerException x) { } 964 try { 965 copy(source, target, (CopyOption[])null); 966 throw new RuntimeException("NullPointerException expected"); 967 } catch (NullPointerException x) { } 968 try { 969 CopyOption[] opts = { REPLACE_EXISTING, null }; 970 copy(source, target, opts); 971 throw new RuntimeException("NullPointerException expected"); 972 } catch (NullPointerException x) { } 973 delete(source); 974 975 /** 976 * Test UOE 977 */ 978 source = createSourceFile(dir1); 979 target = getTargetFile(dir2); 980 try { 981 copy(source, target, new CopyOption() { }); 982 } catch (UnsupportedOperationException x) { } 983 try { 984 copy(source, target, REPLACE_EXISTING, new CopyOption() { }); 985 } catch (UnsupportedOperationException x) { } 986 delete(source); 987 } 988 989 /** 990 * Test copy from an input stream to a file 991 */ testCopyInputStreamToFile()992 static void testCopyInputStreamToFile() throws IOException { 993 testCopyInputStreamToFile(0); 994 for (int i=0; i<100; i++) { 995 testCopyInputStreamToFile(rand.nextInt(32000)); 996 } 997 998 // FileAlreadyExistsException 999 Path target = createTempFile("blah", null); 1000 try { 1001 InputStream in = new ByteArrayInputStream(new byte[0]); 1002 try { 1003 copy(in, target); 1004 throw new RuntimeException("FileAlreadyExistsException expected"); 1005 } catch (FileAlreadyExistsException ignore) { } 1006 } finally { 1007 delete(target); 1008 } 1009 Path tmpdir = createTempDirectory("blah"); 1010 try { 1011 if (TestUtil.supportsLinks(tmpdir)) { 1012 Path link = createSymbolicLink(tmpdir.resolve("link"), 1013 tmpdir.resolve("target")); 1014 try { 1015 InputStream in = new ByteArrayInputStream(new byte[0]); 1016 try { 1017 copy(in, link); 1018 throw new RuntimeException("FileAlreadyExistsException expected"); 1019 } catch (FileAlreadyExistsException ignore) { } 1020 } finally { 1021 delete(link); 1022 } 1023 } 1024 } finally { 1025 delete(tmpdir); 1026 } 1027 1028 1029 // nulls 1030 try { 1031 copy((InputStream)null, target); 1032 throw new RuntimeException("NullPointerException expected"); 1033 } catch (NullPointerException ignore) { } 1034 try { 1035 copy(new ByteArrayInputStream(new byte[0]), (Path)null); 1036 throw new RuntimeException("NullPointerException expected"); 1037 } catch (NullPointerException ignore) { } 1038 } 1039 testCopyInputStreamToFile(int size)1040 static void testCopyInputStreamToFile(int size) throws IOException { 1041 Path tmpdir = createTempDirectory("blah"); 1042 Path source = tmpdir.resolve("source"); 1043 Path target = tmpdir.resolve("target"); 1044 try { 1045 boolean testReplaceExisting = rand.nextBoolean(); 1046 1047 // create source file 1048 byte[] b = new byte[size]; 1049 rand.nextBytes(b); 1050 write(source, b); 1051 1052 // target file might already exist 1053 if (testReplaceExisting && rand.nextBoolean()) { 1054 write(target, new byte[rand.nextInt(512)]); 1055 } 1056 1057 // copy from stream to file 1058 InputStream in = new FileInputStream(source.toFile()); 1059 try { 1060 long n; 1061 if (testReplaceExisting) { 1062 n = copy(in, target, StandardCopyOption.REPLACE_EXISTING); 1063 } else { 1064 n = copy(in, target); 1065 } 1066 assertTrue(in.read() == -1); // EOF 1067 assertTrue(n == size); 1068 assertTrue(size(target) == size); 1069 } finally { 1070 in.close(); 1071 } 1072 1073 // check file 1074 byte[] read = readAllBytes(target); 1075 assertTrue(Arrays.equals(read, b)); 1076 1077 } finally { 1078 deleteIfExists(source); 1079 deleteIfExists(target); 1080 delete(tmpdir); 1081 } 1082 } 1083 1084 /** 1085 * Test copy from file to output stream 1086 */ testCopyFileToOuputStream()1087 static void testCopyFileToOuputStream() throws IOException { 1088 testCopyFileToOuputStream(0); 1089 for (int i=0; i<100; i++) { 1090 testCopyFileToOuputStream(rand.nextInt(32000)); 1091 } 1092 1093 // nulls 1094 try { 1095 copy((Path)null, new ByteArrayOutputStream()); 1096 throw new RuntimeException("NullPointerException expected"); 1097 } catch (NullPointerException ignore) { } 1098 try { 1099 Path source = createTempFile("blah", null); 1100 delete(source); 1101 copy(source, (OutputStream)null); 1102 throw new RuntimeException("NullPointerException expected"); 1103 } catch (NullPointerException ignore) { } 1104 } 1105 testCopyFileToOuputStream(int size)1106 static void testCopyFileToOuputStream(int size) throws IOException { 1107 Path source = createTempFile("blah", null); 1108 try { 1109 byte[] b = new byte[size]; 1110 rand.nextBytes(b); 1111 write(source, b); 1112 1113 ByteArrayOutputStream out = new ByteArrayOutputStream(); 1114 1115 long n = copy(source, out); 1116 assertTrue(n == size); 1117 assertTrue(out.size() == size); 1118 1119 byte[] read = out.toByteArray(); 1120 assertTrue(Arrays.equals(read, b)); 1121 1122 // check output stream is open 1123 out.write(0); 1124 assertTrue(out.size() == size+1); 1125 } finally { 1126 delete(source); 1127 } 1128 } 1129 assertTrue(boolean value)1130 static void assertTrue(boolean value) { 1131 if (!value) 1132 throw new RuntimeException("Assertion failed"); 1133 } 1134 assertTrue(boolean value, String format, Object... args)1135 static void assertTrue(boolean value, String format, Object... args) { 1136 if (!value) { 1137 System.err.format(format, args); 1138 throw new RuntimeException("Assertion failed"); 1139 } 1140 } 1141 1142 // computes simple hash of the given file computeHash(Path file)1143 static int computeHash(Path file) throws IOException { 1144 int h = 0; 1145 1146 try (InputStream in = newInputStream(file)) { 1147 byte[] buf = new byte[1024]; 1148 int n; 1149 do { 1150 n = in.read(buf); 1151 for (int i=0; i<n; i++) { 1152 h = 31*h + (buf[i] & 0xff); 1153 } 1154 } while (n > 0); 1155 } 1156 return h; 1157 } 1158 1159 // create file of random size in given directory createSourceFile(Path dir)1160 static Path createSourceFile(Path dir) throws IOException { 1161 String name = "source" + Integer.toString(rand.nextInt()); 1162 Path file = dir.resolve(name); 1163 createFile(file); 1164 byte[] bytes = new byte[rand.nextInt(128*1024)]; 1165 rand.nextBytes(bytes); 1166 try (OutputStream out = newOutputStream(file)) { 1167 out.write(bytes); 1168 } 1169 randomizeAttributes(file); 1170 return file; 1171 } 1172 1173 // create directory in the given directory createSourceDirectory(Path dir)1174 static Path createSourceDirectory(Path dir) throws IOException { 1175 String name = "sourcedir" + Integer.toString(rand.nextInt()); 1176 Path subdir = dir.resolve(name); 1177 createDirectory(subdir); 1178 randomizeAttributes(subdir); 1179 return subdir; 1180 } 1181 1182 // "randomize" the file attributes of the given file. randomizeAttributes(Path file)1183 static void randomizeAttributes(Path file) throws IOException { 1184 boolean isDirectory = isDirectory(file, NOFOLLOW_LINKS); 1185 1186 if (Platform.isWindows()) { 1187 DosFileAttributeView view = 1188 getFileAttributeView(file, DosFileAttributeView.class, NOFOLLOW_LINKS); 1189 // only set or unset the hidden attribute 1190 view.setHidden(heads()); 1191 } else { 1192 Set<PosixFilePermission> perms = 1193 getPosixFilePermissions(file, NOFOLLOW_LINKS); 1194 PosixFilePermission[] toChange = { 1195 PosixFilePermission.GROUP_READ, 1196 PosixFilePermission.GROUP_WRITE, 1197 PosixFilePermission.GROUP_EXECUTE, 1198 PosixFilePermission.OTHERS_READ, 1199 PosixFilePermission.OTHERS_WRITE, 1200 PosixFilePermission.OTHERS_EXECUTE 1201 }; 1202 for (PosixFilePermission perm: toChange) { 1203 if (heads()) { 1204 perms.add(perm); 1205 } else { 1206 perms.remove(perm); 1207 } 1208 } 1209 setPosixFilePermissions(file, perms); 1210 } 1211 1212 boolean addUserDefinedFileAttributes = heads() && 1213 getFileStore(file).supportsFileAttributeView("xattr"); 1214 1215 // remove this when copying a direcory copies its named streams 1216 if (Platform.isWindows() && isDirectory) 1217 addUserDefinedFileAttributes = false; 1218 1219 if (addUserDefinedFileAttributes) { 1220 UserDefinedFileAttributeView view = 1221 getFileAttributeView(file, UserDefinedFileAttributeView.class); 1222 int n = rand.nextInt(16); 1223 while (n > 0) { 1224 byte[] value = new byte[1 + rand.nextInt(100)]; 1225 view.write("user." + Integer.toString(n), ByteBuffer.wrap(value)); 1226 n--; 1227 } 1228 } 1229 } 1230 1231 // create name for file in given directory getTargetFile(Path dir)1232 static Path getTargetFile(Path dir) throws IOException { 1233 String name = "target" + Integer.toString(rand.nextInt()); 1234 return dir.resolve(name); 1235 } 1236 } 1237