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