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();
heads()45     static boolean heads() { return rand.nextBoolean(); }
46     private static boolean testPosixAttributes = false;
47 
main(String[] args)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 
checkBasicAttributes(BasicFileAttributes attrs1, BasicFileAttributes attrs2)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 
checkPosixAttributes(PosixFileAttributes attrs1, PosixFileAttributes attrs2)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 
checkDosAttributes(DosFileAttributes attrs1, DosFileAttributes attrs2)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 
checkUserDefinedFileAttributes(Map<String,ByteBuffer> attrs1, Map<String,ByteBuffer> attrs2)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 
readUserDefinedFileAttributes(Path file)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
moveAndVerify(Path source, Path target, CopyOption... options)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      */
testMove(Path dir1, Path dir2, boolean supportsLinks)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
copyAndVerify(Path source, Path target, CopyOption... options)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") || os.endsWith("BSD")) &&
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      */
testCopyFileToFile(Path dir1, Path dir2, boolean supportsLinks)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      */
testCopyInputStreamToFile()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 
testCopyInputStreamToFile(int size)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      */
testCopyFileToOuputStream()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 
testCopyFileToOuputStream(int size)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 
assertTrue(boolean value)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
computeHash(Path 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
createSourceFile(Path dir)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
createSourceDirectory(Path dir)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.
randomizeAttributes(Path 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") || os.endsWith("BSD");
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
getTargetFile(Path dir)1209     static Path getTargetFile(Path dir) throws IOException {
1210         String name = "target" + Integer.toString(rand.nextInt());
1211         return dir.resolve(name);
1212     }
1213  }
1214