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