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