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