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