|
1 /* |
|
2 * Copyright 2008-2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
20 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
21 * have any questions. |
|
22 */ |
|
23 |
|
24 /* @test |
|
25 * @bug 4313887 |
|
26 * @summary Unit test for java.nio.file.Path copyTo/moveTo methods |
|
27 * @library .. |
|
28 */ |
|
29 |
|
30 import java.nio.ByteBuffer; |
|
31 import java.nio.file.*; |
|
32 import static java.nio.file.StandardCopyOption.*; |
|
33 import static java.nio.file.LinkOption.*; |
|
34 import java.nio.file.attribute.*; |
|
35 import java.io.*; |
|
36 import java.util.*; |
|
37 |
|
38 public class CopyAndMove { |
|
39 static final Random rand = new Random(); |
|
40 static boolean heads() { return rand.nextBoolean(); } |
|
41 static boolean supportsLinks; |
|
42 |
|
43 public static void main(String[] args) throws Exception { |
|
44 Path dir1 = TestUtil.createTemporaryDirectory(); |
|
45 try { |
|
46 supportsLinks = TestUtil.supportsLinks(dir1); |
|
47 |
|
48 // Exercise copyTo |
|
49 doCopyTests(dir1); |
|
50 |
|
51 // Exercise moveTo |
|
52 // if test.dir differs to temporary file system then can test |
|
53 // moving between devices |
|
54 String testDir = System.getProperty("test.dir"); |
|
55 Path dir2 = (testDir != null) ? Paths.get(testDir) : dir1; |
|
56 doMoveTests(dir1, dir2); |
|
57 |
|
58 } finally { |
|
59 TestUtil.removeAll(dir1); |
|
60 } |
|
61 } |
|
62 |
|
63 static void checkBasicAttributes(BasicFileAttributes attrs1, |
|
64 BasicFileAttributes attrs2) |
|
65 { |
|
66 // check file type |
|
67 assertTrue(attrs1.isRegularFile() == attrs2.isRegularFile()); |
|
68 assertTrue(attrs1.isDirectory() == attrs2.isDirectory()); |
|
69 assertTrue(attrs1.isSymbolicLink() == attrs2.isSymbolicLink()); |
|
70 assertTrue(attrs1.isOther() == attrs2.isOther()); |
|
71 |
|
72 // check last modified time (assume millisecond precision) |
|
73 long time1 = attrs1.resolution().toMillis(attrs1.lastModifiedTime()); |
|
74 long time2 = attrs1.resolution().toMillis(attrs2.lastModifiedTime()); |
|
75 assertTrue(time1 == time2); |
|
76 |
|
77 // check size |
|
78 if (attrs1.isRegularFile()) |
|
79 assertTrue(attrs1.size() == attrs2.size()); |
|
80 } |
|
81 |
|
82 static void checkPosixAttributes(PosixFileAttributes attrs1, |
|
83 PosixFileAttributes attrs2) |
|
84 { |
|
85 assertTrue(attrs1.permissions().equals(attrs2.permissions())); |
|
86 assertTrue(attrs1.owner().equals(attrs2.owner())); |
|
87 assertTrue(attrs1.group().equals(attrs2.group())); |
|
88 } |
|
89 |
|
90 static void checkDosAttributes(DosFileAttributes attrs1, |
|
91 DosFileAttributes attrs2) |
|
92 { |
|
93 assertTrue(attrs1.isReadOnly() == attrs2.isReadOnly()); |
|
94 assertTrue(attrs1.isHidden() == attrs2.isHidden()); |
|
95 assertTrue(attrs1.isArchive() == attrs2.isArchive()); |
|
96 assertTrue(attrs1.isSystem() == attrs2.isSystem()); |
|
97 } |
|
98 |
|
99 static void checkUserDefinedFileAttributes(Map<String,ByteBuffer> attrs1, |
|
100 Map<String,ByteBuffer> attrs2) |
|
101 { |
|
102 assert attrs1.size() == attrs2.size(); |
|
103 for (String name: attrs1.keySet()) { |
|
104 ByteBuffer bb1 = attrs1.get(name); |
|
105 ByteBuffer bb2 = attrs2.get(name); |
|
106 assertTrue(bb2 != null); |
|
107 assertTrue(bb1.equals(bb2)); |
|
108 } |
|
109 } |
|
110 |
|
111 static Map<String,ByteBuffer> readUserDefinedFileAttributes(Path file) |
|
112 throws IOException |
|
113 { |
|
114 UserDefinedFileAttributeView view = file |
|
115 .getFileAttributeView(UserDefinedFileAttributeView.class); |
|
116 Map<String,ByteBuffer> result = new HashMap<String,ByteBuffer>(); |
|
117 for (String name: view.list()) { |
|
118 int size = view.size(name); |
|
119 ByteBuffer bb = ByteBuffer.allocate(size); |
|
120 int n = view.read(name, bb); |
|
121 assertTrue(n == size); |
|
122 bb.flip(); |
|
123 result.put(name, bb); |
|
124 } |
|
125 return result; |
|
126 } |
|
127 |
|
128 // move source to target with verification |
|
129 static void moveAndVerify(Path source, Path target, CopyOption... options) |
|
130 throws IOException |
|
131 { |
|
132 // read attributes before file is moved |
|
133 BasicFileAttributes basicAttributes = null; |
|
134 PosixFileAttributes posixAttributes = null; |
|
135 DosFileAttributes dosAttributes = null; |
|
136 Map<String,ByteBuffer> namedAttributes = null; |
|
137 |
|
138 // get file attributes of source file |
|
139 String os = System.getProperty("os.name"); |
|
140 if (os.equals("SunOS") || os.equals("Linux")) { |
|
141 posixAttributes = Attributes.readPosixFileAttributes(source, NOFOLLOW_LINKS); |
|
142 basicAttributes = posixAttributes; |
|
143 } |
|
144 if (os.startsWith("Windows")) { |
|
145 dosAttributes = Attributes.readDosFileAttributes(source, NOFOLLOW_LINKS); |
|
146 basicAttributes = dosAttributes; |
|
147 } |
|
148 if (basicAttributes == null) |
|
149 basicAttributes = Attributes.readBasicFileAttributes(source, NOFOLLOW_LINKS); |
|
150 |
|
151 // hash file contents if regular file |
|
152 int hash = (basicAttributes.isRegularFile()) ? computeHash(source) : 0; |
|
153 |
|
154 // record link target if symbolic link |
|
155 Path linkTarget = null; |
|
156 if (basicAttributes.isSymbolicLink()) |
|
157 linkTarget = source.readSymbolicLink(); |
|
158 |
|
159 // read named attributes if available (and file is not a sym link) |
|
160 if (!basicAttributes.isSymbolicLink() && |
|
161 source.getFileStore().supportsFileAttributeView("xattr")) |
|
162 { |
|
163 namedAttributes = readUserDefinedFileAttributes(source); |
|
164 } |
|
165 |
|
166 // move file |
|
167 source.moveTo(target, options); |
|
168 |
|
169 // verify source does not exist |
|
170 assertTrue(source.notExists()); |
|
171 |
|
172 // verify file contents |
|
173 if (basicAttributes.isRegularFile()) { |
|
174 if (computeHash(target) != hash) |
|
175 throw new RuntimeException("Failed to verify move of regular file"); |
|
176 } |
|
177 |
|
178 // verify link target |
|
179 if (basicAttributes.isSymbolicLink()) { |
|
180 if (!target.readSymbolicLink().equals(linkTarget)) |
|
181 throw new RuntimeException("Failed to verify move of symbolic link"); |
|
182 } |
|
183 |
|
184 // verify basic attributes |
|
185 checkBasicAttributes(basicAttributes, |
|
186 Attributes.readBasicFileAttributes(target, NOFOLLOW_LINKS)); |
|
187 |
|
188 // verify POSIX attributes |
|
189 if (posixAttributes != null && !basicAttributes.isSymbolicLink()) { |
|
190 checkPosixAttributes(posixAttributes, |
|
191 Attributes.readPosixFileAttributes(target, NOFOLLOW_LINKS)); |
|
192 } |
|
193 |
|
194 // verify DOS attributes |
|
195 if (dosAttributes != null && !basicAttributes.isSymbolicLink()) { |
|
196 checkDosAttributes(dosAttributes, |
|
197 Attributes.readDosFileAttributes(target, NOFOLLOW_LINKS)); |
|
198 } |
|
199 |
|
200 // verify named attributes |
|
201 if (namedAttributes != null && |
|
202 target.getFileStore().supportsFileAttributeView("xattr")) |
|
203 { |
|
204 checkUserDefinedFileAttributes(namedAttributes, readUserDefinedFileAttributes(target)); |
|
205 } |
|
206 } |
|
207 |
|
208 /** |
|
209 * Tests all possible ways to invoke moveTo |
|
210 */ |
|
211 static void doMoveTests(Path dir1, Path dir2) throws IOException { |
|
212 Path source, target, entry; |
|
213 |
|
214 boolean sameDevice = dir1.getFileStore().equals(dir2.getFileStore()); |
|
215 |
|
216 // -- regular file -- |
|
217 |
|
218 /** |
|
219 * Test: move regular file, target does not exist |
|
220 */ |
|
221 source = createSourceFile(dir1); |
|
222 target = getTargetFile(dir1); |
|
223 moveAndVerify(source, target); |
|
224 target.delete(); |
|
225 |
|
226 /** |
|
227 * Test: move regular file, target exists |
|
228 */ |
|
229 source = createSourceFile(dir1); |
|
230 target = getTargetFile(dir1).createFile(); |
|
231 try { |
|
232 moveAndVerify(source, target); |
|
233 throw new RuntimeException("FileAlreadyExistsException expected"); |
|
234 } catch (FileAlreadyExistsException x) { |
|
235 } |
|
236 target.delete(); |
|
237 target.createDirectory(); |
|
238 try { |
|
239 moveAndVerify(source, target); |
|
240 throw new RuntimeException("FileAlreadyExistsException expected"); |
|
241 } catch (FileAlreadyExistsException x) { |
|
242 } |
|
243 source.delete(); |
|
244 target.delete(); |
|
245 |
|
246 /** |
|
247 * Test: move regular file, target does not exist |
|
248 */ |
|
249 source = createSourceFile(dir1); |
|
250 target = getTargetFile(dir1); |
|
251 moveAndVerify(source, target, REPLACE_EXISTING); |
|
252 target.delete(); |
|
253 |
|
254 /** |
|
255 * Test: move regular file, target exists |
|
256 */ |
|
257 source = createSourceFile(dir1); |
|
258 target = getTargetFile(dir1).createFile(); |
|
259 moveAndVerify(source, target, REPLACE_EXISTING); |
|
260 target.delete(); |
|
261 |
|
262 /** |
|
263 * Test: move regular file, target exists and is empty directory |
|
264 */ |
|
265 source = createSourceFile(dir1); |
|
266 target = getTargetFile(dir1).createDirectory(); |
|
267 moveAndVerify(source, target, REPLACE_EXISTING); |
|
268 target.delete(); |
|
269 |
|
270 /** |
|
271 * Test: move regular file, target exists and is non-empty directory |
|
272 */ |
|
273 source = createSourceFile(dir1); |
|
274 target = getTargetFile(dir1).createDirectory(); |
|
275 entry = target.resolve("foo").createFile(); |
|
276 try { |
|
277 moveAndVerify(source, target); |
|
278 throw new RuntimeException("FileAlreadyExistsException expected"); |
|
279 } catch (FileAlreadyExistsException x) { |
|
280 } |
|
281 entry.delete(); |
|
282 source.delete(); |
|
283 target.delete(); |
|
284 |
|
285 /** |
|
286 * Test atomic move of regular file (same file store) |
|
287 */ |
|
288 source = createSourceFile(dir1); |
|
289 target = getTargetFile(dir1); |
|
290 moveAndVerify(source, target, ATOMIC_MOVE); |
|
291 target.delete(); |
|
292 |
|
293 /** |
|
294 * Test atomic move of regular file (different file store) |
|
295 */ |
|
296 if (!sameDevice) { |
|
297 source = createSourceFile(dir1); |
|
298 target = getTargetFile(dir2); |
|
299 try { |
|
300 moveAndVerify(source, target, ATOMIC_MOVE); |
|
301 throw new RuntimeException("AtomicMoveNotSupportedException expected"); |
|
302 } catch (AtomicMoveNotSupportedException x) { |
|
303 } |
|
304 source.delete(); |
|
305 } |
|
306 |
|
307 // -- directories -- |
|
308 |
|
309 /* |
|
310 * Test: move empty directory, target does not exist |
|
311 */ |
|
312 source = createSourceDirectory(dir1); |
|
313 target = getTargetFile(dir1); |
|
314 moveAndVerify(source, target); |
|
315 target.delete(); |
|
316 |
|
317 /** |
|
318 * Test: move empty directory, target exists |
|
319 */ |
|
320 source = createSourceDirectory(dir1); |
|
321 target = getTargetFile(dir1).createFile(); |
|
322 try { |
|
323 moveAndVerify(source, target); |
|
324 throw new RuntimeException("FileAlreadyExistsException expected"); |
|
325 } catch (FileAlreadyExistsException x) { |
|
326 } |
|
327 target.delete(); |
|
328 target.createDirectory(); |
|
329 try { |
|
330 moveAndVerify(source, target); |
|
331 throw new RuntimeException("FileAlreadyExistsException expected"); |
|
332 } catch (FileAlreadyExistsException x) { |
|
333 } |
|
334 source.delete(); |
|
335 target.delete(); |
|
336 |
|
337 /** |
|
338 * Test: move empty directory, target does not exist |
|
339 */ |
|
340 source = createSourceDirectory(dir1); |
|
341 target = getTargetFile(dir1); |
|
342 moveAndVerify(source, target, REPLACE_EXISTING); |
|
343 target.delete(); |
|
344 |
|
345 /** |
|
346 * Test: move empty directory, target exists |
|
347 */ |
|
348 source = createSourceDirectory(dir1); |
|
349 target = getTargetFile(dir1).createFile(); |
|
350 moveAndVerify(source, target, REPLACE_EXISTING); |
|
351 target.delete(); |
|
352 |
|
353 /** |
|
354 * Test: move empty, target exists and is empty directory |
|
355 */ |
|
356 source = createSourceDirectory(dir1); |
|
357 target = getTargetFile(dir1).createDirectory(); |
|
358 moveAndVerify(source, target, REPLACE_EXISTING); |
|
359 target.delete(); |
|
360 |
|
361 /** |
|
362 * Test: move empty directory, target exists and is non-empty directory |
|
363 */ |
|
364 source = createSourceDirectory(dir1); |
|
365 target = getTargetFile(dir1).createDirectory(); |
|
366 entry = target.resolve("foo").createFile(); |
|
367 try { |
|
368 moveAndVerify(source, target, REPLACE_EXISTING); |
|
369 throw new RuntimeException("FileAlreadyExistsException expected"); |
|
370 } catch (FileAlreadyExistsException x) { |
|
371 } |
|
372 entry.delete(); |
|
373 source.delete(); |
|
374 target.delete(); |
|
375 |
|
376 /** |
|
377 * Test: move non-empty directory (same file system) |
|
378 */ |
|
379 source = createSourceDirectory(dir1); |
|
380 source.resolve("foo").createFile(); |
|
381 target = getTargetFile(dir1); |
|
382 moveAndVerify(source, target); |
|
383 target.resolve("foo").delete(); |
|
384 target.delete(); |
|
385 |
|
386 /** |
|
387 * Test: move non-empty directory (different file store) |
|
388 */ |
|
389 if (!sameDevice) { |
|
390 source = createSourceDirectory(dir1); |
|
391 source.resolve("foo").createFile(); |
|
392 target = getTargetFile(dir2); |
|
393 try { |
|
394 moveAndVerify(source, target); |
|
395 throw new RuntimeException("IOException expected"); |
|
396 } catch (IOException x) { |
|
397 } |
|
398 source.resolve("foo").delete(); |
|
399 source.delete(); |
|
400 } |
|
401 |
|
402 /** |
|
403 * Test atomic move of directory (same file store) |
|
404 */ |
|
405 source = createSourceDirectory(dir1); |
|
406 source.resolve("foo").createFile(); |
|
407 target = getTargetFile(dir1); |
|
408 moveAndVerify(source, target, ATOMIC_MOVE); |
|
409 target.resolve("foo").delete(); |
|
410 target.delete(); |
|
411 |
|
412 // -- symbolic links -- |
|
413 |
|
414 /** |
|
415 * Test: Move symbolic link to file, target does not exist |
|
416 */ |
|
417 if (supportsLinks) { |
|
418 Path tmp = createSourceFile(dir1); |
|
419 source = dir1.resolve("link").createSymbolicLink(tmp); |
|
420 target = getTargetFile(dir1); |
|
421 moveAndVerify(source, target); |
|
422 target.delete(); |
|
423 tmp.delete(); |
|
424 } |
|
425 |
|
426 /** |
|
427 * Test: Move symbolic link to directory, target does not exist |
|
428 */ |
|
429 if (supportsLinks) { |
|
430 source = dir1.resolve("link").createSymbolicLink(dir2); |
|
431 target = getTargetFile(dir1); |
|
432 moveAndVerify(source, target); |
|
433 target.delete(); |
|
434 } |
|
435 |
|
436 /** |
|
437 * Test: Move broken symbolic link, target does not exists |
|
438 */ |
|
439 if (supportsLinks) { |
|
440 Path tmp = Paths.get("doesnotexist"); |
|
441 source = dir1.resolve("link").createSymbolicLink(tmp); |
|
442 target = getTargetFile(dir1); |
|
443 moveAndVerify(source, target); |
|
444 target.delete(); |
|
445 } |
|
446 |
|
447 /** |
|
448 * Test: Move symbolic link, target exists |
|
449 */ |
|
450 if (supportsLinks) { |
|
451 source = dir1.resolve("link").createSymbolicLink(dir2); |
|
452 target = getTargetFile(dir1).createFile(); |
|
453 try { |
|
454 moveAndVerify(source, target); |
|
455 throw new RuntimeException("FileAlreadyExistsException expected"); |
|
456 } catch (FileAlreadyExistsException x) { |
|
457 } |
|
458 source.delete(); |
|
459 target.delete(); |
|
460 } |
|
461 |
|
462 /** |
|
463 * Test: Move regular file, target exists |
|
464 */ |
|
465 if (supportsLinks) { |
|
466 source = dir1.resolve("link").createSymbolicLink(dir2); |
|
467 target = getTargetFile(dir1).createFile(); |
|
468 moveAndVerify(source, target, REPLACE_EXISTING); |
|
469 target.delete(); |
|
470 } |
|
471 |
|
472 /** |
|
473 * Test: move symbolic link, target exists and is empty directory |
|
474 */ |
|
475 if (supportsLinks) { |
|
476 source = dir1.resolve("link").createSymbolicLink(dir2); |
|
477 target = getTargetFile(dir1).createDirectory(); |
|
478 moveAndVerify(source, target, REPLACE_EXISTING); |
|
479 target.delete(); |
|
480 } |
|
481 |
|
482 /** |
|
483 * Test: symbolic link, target exists and is non-empty directory |
|
484 */ |
|
485 if (supportsLinks) { |
|
486 source = dir1.resolve("link").createSymbolicLink(dir2); |
|
487 target = getTargetFile(dir1).createDirectory(); |
|
488 entry = target.resolve("foo").createFile(); |
|
489 try { |
|
490 moveAndVerify(source, target); |
|
491 throw new RuntimeException("FileAlreadyExistsException expected"); |
|
492 } catch (FileAlreadyExistsException x) { |
|
493 } |
|
494 entry.delete(); |
|
495 source.delete(); |
|
496 target.delete(); |
|
497 } |
|
498 |
|
499 /** |
|
500 * Test atomic move of symbolic link (same file store) |
|
501 */ |
|
502 if (supportsLinks) { |
|
503 source = dir1.resolve("link").createSymbolicLink(dir1); |
|
504 target = getTargetFile(dir1).createFile(); |
|
505 moveAndVerify(source, target, REPLACE_EXISTING); |
|
506 target.delete(); |
|
507 } |
|
508 |
|
509 // -- misc. tests -- |
|
510 |
|
511 /** |
|
512 * Test nulls |
|
513 */ |
|
514 source = createSourceFile(dir1); |
|
515 target = getTargetFile(dir1); |
|
516 try { |
|
517 source.moveTo(null); |
|
518 throw new RuntimeException("NullPointerException expected"); |
|
519 } catch (NullPointerException x) { } |
|
520 try { |
|
521 source.moveTo(target, (CopyOption[])null); |
|
522 throw new RuntimeException("NullPointerException expected"); |
|
523 } catch (NullPointerException x) { } |
|
524 try { |
|
525 CopyOption[] opts = { REPLACE_EXISTING, null }; |
|
526 source.moveTo(target, opts); |
|
527 throw new RuntimeException("NullPointerException expected"); |
|
528 } catch (NullPointerException x) { } |
|
529 source.delete(); |
|
530 |
|
531 /** |
|
532 * Test UOE |
|
533 */ |
|
534 source = createSourceFile(dir1); |
|
535 target = getTargetFile(dir1); |
|
536 try { |
|
537 source.moveTo(target, new CopyOption() { }); |
|
538 } catch (UnsupportedOperationException x) { } |
|
539 try { |
|
540 source.moveTo(target, REPLACE_EXISTING, new CopyOption() { }); |
|
541 } catch (UnsupportedOperationException x) { } |
|
542 source.delete(); |
|
543 } |
|
544 |
|
545 // copy source to target with verification |
|
546 static void copyAndVerify(Path source, Path target, CopyOption... options) |
|
547 throws IOException |
|
548 { |
|
549 source.copyTo(target, options); |
|
550 |
|
551 // get attributes of source and target file to verify copy |
|
552 boolean followLinks = true; |
|
553 LinkOption[] linkOptions = new LinkOption[0]; |
|
554 boolean copyAttributes = false; |
|
555 for (CopyOption opt : options) { |
|
556 if (opt == NOFOLLOW_LINKS) { |
|
557 followLinks = false; |
|
558 linkOptions = new LinkOption[] { NOFOLLOW_LINKS }; |
|
559 } |
|
560 if (opt == COPY_ATTRIBUTES) |
|
561 copyAttributes = true; |
|
562 } |
|
563 BasicFileAttributes basicAttributes = Attributes |
|
564 .readBasicFileAttributes(source, linkOptions); |
|
565 |
|
566 // check hash if regular file |
|
567 if (basicAttributes.isRegularFile()) |
|
568 assertTrue(computeHash(source) == computeHash(target)); |
|
569 |
|
570 // check link target if symbolic link |
|
571 if (basicAttributes.isSymbolicLink()) |
|
572 assert( source.readSymbolicLink().equals(target.readSymbolicLink())); |
|
573 |
|
574 // check that attributes are copied |
|
575 if (copyAttributes && followLinks) { |
|
576 checkBasicAttributes(basicAttributes, |
|
577 Attributes.readBasicFileAttributes(source, linkOptions)); |
|
578 |
|
579 // check POSIX attributes are copied |
|
580 String os = System.getProperty("os.name"); |
|
581 if (os.equals("SunOS") || os.equals("Linux")) { |
|
582 checkPosixAttributes( |
|
583 Attributes.readPosixFileAttributes(source, linkOptions), |
|
584 Attributes.readPosixFileAttributes(target, linkOptions)); |
|
585 } |
|
586 |
|
587 // check DOS attributes are copied |
|
588 if (os.startsWith("Windows")) { |
|
589 checkDosAttributes( |
|
590 Attributes.readDosFileAttributes(source, linkOptions), |
|
591 Attributes.readDosFileAttributes(target, linkOptions)); |
|
592 } |
|
593 |
|
594 // check named attributes are copied |
|
595 if (followLinks && |
|
596 source.getFileStore().supportsFileAttributeView("xattr") && |
|
597 target.getFileStore().supportsFileAttributeView("xattr")) |
|
598 { |
|
599 checkUserDefinedFileAttributes(readUserDefinedFileAttributes(source), |
|
600 readUserDefinedFileAttributes(target)); |
|
601 } |
|
602 } |
|
603 } |
|
604 |
|
605 /** |
|
606 * Tests all possible ways to invoke copyTo |
|
607 */ |
|
608 static void doCopyTests(Path dir) throws IOException { |
|
609 Path source, target, link, entry; |
|
610 |
|
611 // -- regular file -- |
|
612 |
|
613 /** |
|
614 * Test: move regular file, target does not exist |
|
615 */ |
|
616 source = createSourceFile(dir); |
|
617 target = getTargetFile(dir); |
|
618 copyAndVerify(source, target); |
|
619 source.delete(); |
|
620 target.delete(); |
|
621 |
|
622 /** |
|
623 * Test: copy regular file, target exists |
|
624 */ |
|
625 source = createSourceFile(dir); |
|
626 target = getTargetFile(dir).createFile(); |
|
627 try { |
|
628 copyAndVerify(source, target); |
|
629 throw new RuntimeException("FileAlreadyExistsException expected"); |
|
630 } catch (FileAlreadyExistsException x) { |
|
631 } |
|
632 target.delete(); |
|
633 target.createDirectory(); |
|
634 try { |
|
635 copyAndVerify(source, target); |
|
636 throw new RuntimeException("FileAlreadyExistsException expected"); |
|
637 } catch (FileAlreadyExistsException x) { |
|
638 } |
|
639 source.delete(); |
|
640 target.delete(); |
|
641 |
|
642 /** |
|
643 * Test: copy regular file, target does not exist |
|
644 */ |
|
645 source = createSourceFile(dir); |
|
646 target = getTargetFile(dir); |
|
647 copyAndVerify(source, target, REPLACE_EXISTING); |
|
648 source.delete(); |
|
649 target.delete(); |
|
650 |
|
651 /** |
|
652 * Test: copy regular file, target exists |
|
653 */ |
|
654 source = createSourceFile(dir); |
|
655 target = getTargetFile(dir).createFile(); |
|
656 copyAndVerify(source, target, REPLACE_EXISTING); |
|
657 source.delete(); |
|
658 target.delete(); |
|
659 |
|
660 /** |
|
661 * Test: copy regular file, target exists and is empty directory |
|
662 */ |
|
663 source = createSourceFile(dir); |
|
664 target = getTargetFile(dir).createDirectory(); |
|
665 copyAndVerify(source, target, REPLACE_EXISTING); |
|
666 source.delete(); |
|
667 target.delete(); |
|
668 |
|
669 /** |
|
670 * Test: copy regular file, target exists and is non-empty directory |
|
671 */ |
|
672 source = createSourceFile(dir); |
|
673 target = getTargetFile(dir).createDirectory(); |
|
674 entry = target.resolve("foo").createFile(); |
|
675 try { |
|
676 copyAndVerify(source, target); |
|
677 throw new RuntimeException("FileAlreadyExistsException expected"); |
|
678 } catch (FileAlreadyExistsException x) { |
|
679 } |
|
680 entry.delete(); |
|
681 source.delete(); |
|
682 target.delete(); |
|
683 |
|
684 /** |
|
685 * Test: copy regular file + attributes |
|
686 */ |
|
687 source = createSourceFile(dir); |
|
688 target = getTargetFile(dir); |
|
689 copyAndVerify(source, target, COPY_ATTRIBUTES); |
|
690 source.delete(); |
|
691 target.delete(); |
|
692 |
|
693 |
|
694 // -- directory -- |
|
695 |
|
696 /* |
|
697 * Test: copy directory, target does not exist |
|
698 */ |
|
699 source = createSourceDirectory(dir); |
|
700 target = getTargetFile(dir); |
|
701 copyAndVerify(source, target); |
|
702 source.delete(); |
|
703 target.delete(); |
|
704 |
|
705 /** |
|
706 * Test: copy directory, target exists |
|
707 */ |
|
708 source = createSourceDirectory(dir); |
|
709 target = getTargetFile(dir).createFile(); |
|
710 try { |
|
711 copyAndVerify(source, target); |
|
712 throw new RuntimeException("FileAlreadyExistsException expected"); |
|
713 } catch (FileAlreadyExistsException x) { |
|
714 } |
|
715 target.delete(); |
|
716 target.createDirectory(); |
|
717 try { |
|
718 copyAndVerify(source, target); |
|
719 throw new RuntimeException("FileAlreadyExistsException expected"); |
|
720 } catch (FileAlreadyExistsException x) { |
|
721 } |
|
722 source.delete(); |
|
723 target.delete(); |
|
724 |
|
725 /** |
|
726 * Test: copy directory, target does not exist |
|
727 */ |
|
728 source = createSourceDirectory(dir); |
|
729 target = getTargetFile(dir); |
|
730 copyAndVerify(source, target, REPLACE_EXISTING); |
|
731 source.delete(); |
|
732 target.delete(); |
|
733 |
|
734 /** |
|
735 * Test: copy directory, target exists |
|
736 */ |
|
737 source = createSourceDirectory(dir); |
|
738 target = getTargetFile(dir).createFile(); |
|
739 copyAndVerify(source, target, REPLACE_EXISTING); |
|
740 source.delete(); |
|
741 target.delete(); |
|
742 |
|
743 /** |
|
744 * Test: copy directory, target exists and is empty directory |
|
745 */ |
|
746 source = createSourceDirectory(dir); |
|
747 target = getTargetFile(dir).createDirectory(); |
|
748 copyAndVerify(source, target, REPLACE_EXISTING); |
|
749 source.delete(); |
|
750 target.delete(); |
|
751 |
|
752 /** |
|
753 * Test: copy directory, target exists and is non-empty directory |
|
754 */ |
|
755 source = createSourceDirectory(dir); |
|
756 target = getTargetFile(dir).createDirectory(); |
|
757 entry = target.resolve("foo").createFile(); |
|
758 try { |
|
759 copyAndVerify(source, target, REPLACE_EXISTING); |
|
760 throw new RuntimeException("FileAlreadyExistsException expected"); |
|
761 } catch (FileAlreadyExistsException x) { |
|
762 } |
|
763 entry.delete(); |
|
764 source.delete(); |
|
765 target.delete(); |
|
766 |
|
767 /* |
|
768 * Test: copy directory + attributes |
|
769 */ |
|
770 source = createSourceDirectory(dir); |
|
771 target = getTargetFile(dir); |
|
772 copyAndVerify(source, target, COPY_ATTRIBUTES); |
|
773 source.delete(); |
|
774 target.delete(); |
|
775 |
|
776 // -- symbolic links -- |
|
777 |
|
778 /** |
|
779 * Test: Follow link |
|
780 */ |
|
781 if (supportsLinks) { |
|
782 source = createSourceFile(dir); |
|
783 link = dir.resolve("link").createSymbolicLink(source); |
|
784 target = getTargetFile(dir); |
|
785 copyAndVerify(link, target); |
|
786 link.delete(); |
|
787 source.delete(); |
|
788 } |
|
789 |
|
790 /** |
|
791 * Test: Copy link (to file) |
|
792 */ |
|
793 if (supportsLinks) { |
|
794 source = createSourceFile(dir); |
|
795 link = dir.resolve("link").createSymbolicLink(source); |
|
796 target = getTargetFile(dir); |
|
797 copyAndVerify(link, target, NOFOLLOW_LINKS); |
|
798 link.delete(); |
|
799 source.delete(); |
|
800 } |
|
801 |
|
802 /** |
|
803 * Test: Copy link (to directory) |
|
804 */ |
|
805 if (supportsLinks) { |
|
806 source = dir.resolve("mydir").createDirectory(); |
|
807 link = dir.resolve("link").createSymbolicLink(source); |
|
808 target = getTargetFile(dir); |
|
809 copyAndVerify(link, target, NOFOLLOW_LINKS); |
|
810 link.delete(); |
|
811 source.delete(); |
|
812 } |
|
813 |
|
814 /** |
|
815 * Test: Copy broken link |
|
816 */ |
|
817 if (supportsLinks) { |
|
818 assertTrue(source.notExists()); |
|
819 link = dir.resolve("link").createSymbolicLink(source); |
|
820 target = getTargetFile(dir); |
|
821 copyAndVerify(link, target, NOFOLLOW_LINKS); |
|
822 link.delete(); |
|
823 } |
|
824 |
|
825 /** |
|
826 * Test: Copy link to UNC (Windows only) |
|
827 */ |
|
828 if (supportsLinks && |
|
829 System.getProperty("os.name").startsWith("Windows")) |
|
830 { |
|
831 Path unc = Paths.get("\\\\rialto\\share\\file"); |
|
832 link = dir.resolve("link").createSymbolicLink(unc); |
|
833 target = getTargetFile(dir); |
|
834 copyAndVerify(link, target, NOFOLLOW_LINKS); |
|
835 link.delete(); |
|
836 } |
|
837 |
|
838 // -- misc. tests -- |
|
839 |
|
840 /** |
|
841 * Test nulls |
|
842 */ |
|
843 source = createSourceFile(dir); |
|
844 target = getTargetFile(dir); |
|
845 try { |
|
846 source.copyTo(null); |
|
847 throw new RuntimeException("NullPointerException expected"); |
|
848 } catch (NullPointerException x) { } |
|
849 try { |
|
850 source.copyTo(target, (CopyOption[])null); |
|
851 throw new RuntimeException("NullPointerException expected"); |
|
852 } catch (NullPointerException x) { } |
|
853 try { |
|
854 CopyOption[] opts = { REPLACE_EXISTING, null }; |
|
855 source.copyTo(target, opts); |
|
856 throw new RuntimeException("NullPointerException expected"); |
|
857 } catch (NullPointerException x) { } |
|
858 source.delete(); |
|
859 |
|
860 /** |
|
861 * Test UOE |
|
862 */ |
|
863 source = createSourceFile(dir); |
|
864 target = getTargetFile(dir); |
|
865 try { |
|
866 source.copyTo(target, new CopyOption() { }); |
|
867 } catch (UnsupportedOperationException x) { } |
|
868 try { |
|
869 source.copyTo(target, REPLACE_EXISTING, new CopyOption() { }); |
|
870 } catch (UnsupportedOperationException x) { } |
|
871 source.delete(); |
|
872 } |
|
873 |
|
874 |
|
875 static void assertTrue(boolean value) { |
|
876 if (!value) |
|
877 throw new RuntimeException("Assertion failed"); |
|
878 } |
|
879 |
|
880 // computes simple hash of the given file |
|
881 static int computeHash(Path file) throws IOException { |
|
882 int h = 0; |
|
883 |
|
884 InputStream in = file.newInputStream(); |
|
885 try { |
|
886 byte[] buf = new byte[1024]; |
|
887 int n; |
|
888 do { |
|
889 n = in.read(buf); |
|
890 for (int i=0; i<n; i++) { |
|
891 h = 31*h + (buf[i] & 0xff); |
|
892 } |
|
893 } while (n > 0); |
|
894 } finally { |
|
895 in.close(); |
|
896 } |
|
897 return h; |
|
898 } |
|
899 |
|
900 // create file of random size in given directory |
|
901 static Path createSourceFile(Path dir) throws IOException { |
|
902 String name = "source" + Integer.toString(rand.nextInt()); |
|
903 Path file = dir.resolve(name).createFile(); |
|
904 byte[] bytes = new byte[rand.nextInt(128*1024)]; |
|
905 rand.nextBytes(bytes); |
|
906 OutputStream out = file.newOutputStream(); |
|
907 try { |
|
908 out.write(bytes); |
|
909 } finally { |
|
910 out.close(); |
|
911 } |
|
912 randomizeAttributes(file); |
|
913 return file; |
|
914 } |
|
915 |
|
916 // create directory in the given directory |
|
917 static Path createSourceDirectory(Path dir) throws IOException { |
|
918 String name = "sourcedir" + Integer.toString(rand.nextInt()); |
|
919 Path subdir = dir.resolve(name).createDirectory(); |
|
920 randomizeAttributes(subdir); |
|
921 return subdir; |
|
922 } |
|
923 |
|
924 // "randomize" the file attributes of the given file. |
|
925 static void randomizeAttributes(Path file) throws IOException { |
|
926 String os = System.getProperty("os.name"); |
|
927 boolean isWindows = os.startsWith("Windows"); |
|
928 boolean isUnix = os.equals("SunOS") || os.equals("Linux"); |
|
929 boolean isDirectory = Attributes.readBasicFileAttributes(file, NOFOLLOW_LINKS) |
|
930 .isDirectory(); |
|
931 |
|
932 if (isUnix) { |
|
933 Set<PosixFilePermission> perms = Attributes |
|
934 .readPosixFileAttributes(file, NOFOLLOW_LINKS).permissions(); |
|
935 PosixFilePermission[] toChange = { |
|
936 PosixFilePermission.GROUP_READ, |
|
937 PosixFilePermission.GROUP_WRITE, |
|
938 PosixFilePermission.GROUP_EXECUTE, |
|
939 PosixFilePermission.OTHERS_READ, |
|
940 PosixFilePermission.OTHERS_WRITE, |
|
941 PosixFilePermission.OTHERS_EXECUTE |
|
942 }; |
|
943 for (PosixFilePermission perm: toChange) { |
|
944 if (heads()) { |
|
945 perms.add(perm); |
|
946 } else { |
|
947 perms.remove(perm); |
|
948 } |
|
949 } |
|
950 Attributes.setPosixFilePermissions(file, perms); |
|
951 } |
|
952 |
|
953 if (isWindows) { |
|
954 DosFileAttributeView view = file |
|
955 .getFileAttributeView(DosFileAttributeView.class, NOFOLLOW_LINKS); |
|
956 // only set or unset the hidden attribute |
|
957 view.setHidden(heads()); |
|
958 } |
|
959 |
|
960 boolean addUserDefinedFileAttributes = heads() && |
|
961 file.getFileStore().supportsFileAttributeView("xattr"); |
|
962 |
|
963 // remove this when copying a direcory copies its named streams |
|
964 if (isWindows && isDirectory) addUserDefinedFileAttributes = false; |
|
965 |
|
966 if (addUserDefinedFileAttributes) { |
|
967 UserDefinedFileAttributeView view = file |
|
968 .getFileAttributeView(UserDefinedFileAttributeView.class); |
|
969 int n = rand.nextInt(16); |
|
970 while (n > 0) { |
|
971 byte[] value = new byte[1 + rand.nextInt(100)]; |
|
972 view.write("user." + Integer.toString(n), ByteBuffer.wrap(value)); |
|
973 n--; |
|
974 } |
|
975 } |
|
976 } |
|
977 |
|
978 // create name for file in given directory |
|
979 static Path getTargetFile(Path dir) throws IOException { |
|
980 String name = "target" + Integer.toString(rand.nextInt()); |
|
981 return dir.resolve(name); |
|
982 } |
|
983 } |