1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.io.file;
19
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertFalse;
22 import static org.junit.jupiter.api.Assertions.assertTrue;
23
24 import java.io.IOException;
25 import java.net.URI;
26 import java.net.URL;
27 import java.nio.file.CopyOption;
28 import java.nio.file.FileSystem;
29 import java.nio.file.FileSystems;
30 import java.nio.file.Files;
31 import java.nio.file.LinkOption;
32 import java.nio.file.Path;
33 import java.nio.file.Paths;
34 import java.util.HashMap;
35 import java.util.Map;
36 import java.util.stream.Stream;
37
38 import org.apache.commons.io.FilenameUtils;
39 import org.apache.commons.io.file.Counters.PathCounters;
40 import org.junit.jupiter.api.Test;
41 import org.junit.jupiter.api.extension.ExtensionContext;
42 import org.junit.jupiter.api.io.TempDir;
43 import org.junit.jupiter.params.ParameterizedTest;
44 import org.junit.jupiter.params.provider.Arguments;
45 import org.junit.jupiter.params.provider.ArgumentsProvider;
46 import org.junit.jupiter.params.provider.ArgumentsSource;
47 import org.junit.jupiter.params.support.ParameterDeclarations;
48
49
50
51
52 class PathUtilsCopyTest extends AbstractTempDirTest {
53
54 private static class CopyOptionsArgumentsProvider implements ArgumentsProvider {
55
56 @Override
57 public Stream<? extends Arguments> provideArguments(final ParameterDeclarations parameters, final ExtensionContext context) {
58 return Stream.of(
59 Arguments.of((Object) new CopyOption[0]),
60 Arguments.of((Object) new CopyOption[] { LinkOption.NOFOLLOW_LINKS })
61 );
62 }
63 }
64
65 private static final String TEST_JAR_NAME = "test.jar";
66
67 private static final String TEST_JAR_PATH = "src/test/resources/org/apache/commons/io/test.jar";
68
69 private FileSystem openArchive(final Path p, final boolean createNew) throws IOException {
70 if (createNew) {
71 final Map<String, String> env = new HashMap<>();
72 env.put("create", "true");
73 final URI fileUri = p.toAbsolutePath().toUri();
74 final URI uri = URI.create("jar:" + fileUri.toASCIIString());
75 return FileSystems.newFileSystem(uri, env, null);
76 }
77 return FileSystems.newFileSystem(p, (ClassLoader) null);
78 }
79
80 @Test
81 void testCopyDirectoryCyclicSymbolicLink() throws Exception {
82
83 final Path sourceDir = Files.createDirectory(tempDirPath.resolve("source"));
84
85 final Path dir1 = Files.createDirectory(sourceDir.resolve("dir1"));
86
87 final Path dir2 = Files.createDirectory(dir1.resolve("dir2"));
88
89
90 Files.createSymbolicLink(dir2.resolve("cyclic-symlink"), dir2.relativize(dir1));
91 final Path targetDir = tempDirPath.resolve("target");
92 PathUtils.copyDirectory(sourceDir, targetDir);
93 assertTrue(Files.exists(targetDir));
94 final Path copyOfDir2 = targetDir.resolve("dir1").resolve("dir2");
95 assertTrue(Files.exists(copyOfDir2));
96 assertTrue(Files.isDirectory(copyOfDir2));
97 assertTrue(Files.exists(copyOfDir2.resolve("cyclic-symlink")));
98 }
99
100 @Test
101 void testCopyDirectoryFollowsAbsoluteSymbolicLinkToDirectory() throws Exception {
102
103 final Path externalDir = Files.createDirectory(tempDirPath.resolve("external"));
104 final Path dir1 = Files.createDirectory(externalDir.resolve("dir1"));
105 final Path file2 = Files.write(dir1.resolve("file2"), PathUtilsTest.BYTE_ARRAY_FIXTURE);
106 final Path sourceDir = Files.createDirectory(tempDirPath.resolve("source"));
107 final Path dir3 = Files.createDirectory(sourceDir.resolve("dir3"));
108 final Path file4 = Files.write(dir3.resolve("file4"), PathUtilsTest.BYTE_ARRAY_FIXTURE);
109 Files.createSymbolicLink(sourceDir.resolve("symlink1"), dir1.toAbsolutePath());
110 Files.createSymbolicLink(sourceDir.resolve("symlink2"), sourceDir.relativize(file2));
111 Files.createSymbolicLink(sourceDir.resolve("symlink3"), sourceDir.relativize(dir3));
112 Files.createSymbolicLink(dir3.resolve("symlink4"), file4.toAbsolutePath());
113 final Path targetDir = tempDirPath.resolve("target");
114
115 final PathCounters pathCounters = PathUtils.copyDirectory(sourceDir, targetDir);
116
117
118
119
120
121
122
123
124
125
126 pathCounters.getByteCounter().get();
127 assertEquals(2L, pathCounters.getDirectoryCounter().get());
128 assertEquals(5L, pathCounters.getFileCounter().get());
129 assertTrue(Files.exists(targetDir.resolve("dir3").resolve("file4")));
130 assertTrue(Files.exists(targetDir.resolve("dir3").resolve("symlink4")));
131 }
132
133 @Test
134 void testCopyDirectoryForDifferentFilesystemsWithAbsolutePath() throws IOException {
135 final Path archivePath = Paths.get(TEST_JAR_PATH);
136 try (FileSystem archive = openArchive(archivePath, false)) {
137
138 Path sourceDir = archive.getPath("dir1");
139 PathUtils.copyDirectory(sourceDir, tempDirPath);
140 assertTrue(Files.exists(tempDirPath.resolve("f1")));
141
142 sourceDir = archive.getPath("/next");
143 PathUtils.copyDirectory(sourceDir, tempDirPath);
144 assertTrue(Files.exists(tempDirPath.resolve("dir")));
145 }
146 }
147
148 @Test
149 void testCopyDirectoryForDifferentFilesystemsWithAbsolutePathReverse() throws IOException {
150 try (FileSystem archive = openArchive(tempDirPath.resolve(TEST_JAR_NAME), true)) {
151
152 Path targetDir = archive.getPath("target");
153 Files.createDirectory(targetDir);
154 final Path sourceDir = Paths.get("src/test/resources/org/apache/commons/io/dirs-2-file-size-2").toAbsolutePath();
155 PathUtils.copyDirectory(sourceDir, targetDir);
156 assertTrue(Files.exists(targetDir.resolve("dirs-a-file-size-1")));
157
158 targetDir = archive.getPath("/");
159 PathUtils.copyDirectory(sourceDir, targetDir);
160 assertTrue(Files.exists(targetDir.resolve("dirs-a-file-size-1")));
161 }
162 }
163
164 @Test
165 void testCopyDirectoryForDifferentFilesystemsWithRelativePath() throws IOException {
166 final Path archivePath = Paths.get(TEST_JAR_PATH);
167 try (FileSystem archive = openArchive(archivePath, false); FileSystem targetArchive = openArchive(tempDirPath.resolve(TEST_JAR_NAME), true)) {
168 final Path targetDir = targetArchive.getPath("targetDir");
169 Files.createDirectory(targetDir);
170
171 Path sourceDir = archive.getPath("next");
172 PathUtils.copyDirectory(sourceDir, targetDir);
173 assertTrue(Files.exists(targetDir.resolve("dir")));
174
175 sourceDir = archive.getPath("/dir1");
176 PathUtils.copyDirectory(sourceDir, targetDir);
177 assertTrue(Files.exists(targetDir.resolve("f1")));
178 }
179 }
180
181 @Test
182 void testCopyDirectoryForDifferentFilesystemsWithRelativePathReverse() throws IOException {
183 try (FileSystem archive = openArchive(tempDirPath.resolve(TEST_JAR_NAME), true)) {
184
185 Path targetDir = archive.getPath("target");
186 Files.createDirectory(targetDir);
187 final Path sourceDir = Paths.get("src/test/resources/org/apache/commons/io/dirs-2-file-size-2");
188 PathUtils.copyDirectory(sourceDir, targetDir);
189 assertTrue(Files.exists(targetDir.resolve("dirs-a-file-size-1")));
190
191 targetDir = archive.getPath("/");
192 PathUtils.copyDirectory(sourceDir, targetDir);
193 assertTrue(Files.exists(targetDir.resolve("dirs-a-file-size-1")));
194 }
195 }
196
197 @ParameterizedTest
198 @ArgumentsSource(CopyOptionsArgumentsProvider.class)
199 void testCopyDirectoryIgnoresBrokenSymbolicLink(final CopyOption... copyOptions) throws Exception {
200 final Path sourceDir = Files.createDirectory(tempDirPath.resolve("source"));
201 final Path dir = Files.createDirectory(sourceDir.resolve("dir"));
202 Files.createSymbolicLink(dir.resolve("broken-symlink"), dir.relativize(sourceDir.resolve("file")));
203 final Path targetDir = tempDirPath.resolve("target");
204 PathUtils.copyDirectory(sourceDir, targetDir, copyOptions);
205 assertTrue(Files.exists(targetDir));
206 final Path copyOfDir = targetDir.resolve("dir");
207 assertTrue(Files.exists(copyOfDir));
208 assertTrue(Files.isDirectory(copyOfDir));
209 assertFalse(Files.exists(copyOfDir.resolve("broken-symlink")));
210 }
211
212
213
214
215
216
217
218
219
220
221
222
223 @Test
224 void testCopyDirectoryPreservesSymlinks(@TempDir final Path tempDir) throws Exception {
225 final Path sourceDir = Files.createDirectory(tempDir.resolve("source"));
226 final Path dir = Files.createDirectory(sourceDir.resolve("dir"));
227 final Path dirLink = Files.createSymbolicLink(sourceDir.resolve("link-to-dir"), dir);
228 assertTrue(Files.exists(dirLink));
229 final Path file = Files.createFile(dir.resolve("file"));
230 final Path fileLink = Files.createSymbolicLink(dir.resolve("link-to-file"), file);
231 assertTrue(Files.exists(fileLink));
232 final Path targetDir = tempDir.resolve("target");
233 PathUtils.copyDirectory(sourceDir, targetDir, LinkOption.NOFOLLOW_LINKS);
234 final Path copyOfDir = targetDir.resolve("dir");
235 assertTrue(Files.exists(copyOfDir));
236 final Path copyOfDirLink = targetDir.resolve("link-to-dir");
237 assertTrue(Files.exists(copyOfDirLink));
238 assertTrue(Files.isSymbolicLink(copyOfDirLink));
239 final Path copyOfFileLink = copyOfDir.resolve("link-to-file");
240 assertTrue(Files.exists(copyOfFileLink));
241 assertTrue(Files.isSymbolicLink(copyOfFileLink));
242 }
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263 @Test
264 void testCopyDirectoryWithNoFollowLinksPreservesAbsoluteSymbolicLinkToDir() throws Exception {
265
266 final Path sourceDir = Files.createDirectory(tempDirPath.resolve("source"));
267 final Path externalDir = Files.createDirectory(tempDirPath.resolve("external"));
268 final Path dir = Files.createDirectory(sourceDir.resolve("dir"));
269
270 Files.createSymbolicLink(dir.resolve("symlink"), externalDir.toAbsolutePath());
271 final Path targetDir = tempDirPath.resolve("target");
272
273 final PathCounters pathCounters = PathUtils.copyDirectory(sourceDir, targetDir, LinkOption.NOFOLLOW_LINKS);
274
275
276 assertEquals(2L, pathCounters.getDirectoryCounter().get());
277
278 assertEquals(1L, pathCounters.getFileCounter().get());
279 final Path copyOfAbsoluteSymlinkToDir = targetDir.resolve("dir").resolve("symlink");
280 assertTrue(Files.isSymbolicLink(copyOfAbsoluteSymlinkToDir));
281 assertTrue(Files.isDirectory(copyOfAbsoluteSymlinkToDir));
282
283 assertEquals(externalDir.toRealPath(), copyOfAbsoluteSymlinkToDir.toRealPath());
284 }
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306 @Test
307 void testCopyDirectoryWithNoFollowLinksPreservesAbsoluteSymbolicLinkToFile() throws Exception {
308
309 final Path externalDir = Files.createDirectory(tempDirPath.resolve("external"));
310 final Path file = Files.write(externalDir.resolve("file"), PathUtilsTest.BYTE_ARRAY_FIXTURE);
311 final Path sourceDir = Files.createDirectory(tempDirPath.resolve("source"));
312 final Path dir = Files.createDirectory(sourceDir.resolve("dir"));
313
314 Files.createSymbolicLink(dir.resolve("symlink"), file.toAbsolutePath());
315 final Path targetDir = tempDirPath.resolve("target");
316
317 final PathCounters pathCounters = PathUtils.copyDirectory(sourceDir, targetDir, LinkOption.NOFOLLOW_LINKS);
318
319
320 assertEquals(2L, pathCounters.getDirectoryCounter().get());
321 assertEquals(1L, pathCounters.getFileCounter().get());
322 final Path copyOfAbsoluteSymlinkToFile = targetDir.resolve("dir").resolve("symlink");
323 assertTrue(Files.isSymbolicLink(copyOfAbsoluteSymlinkToFile));
324 assertTrue(Files.isRegularFile(copyOfAbsoluteSymlinkToFile));
325
326 assertEquals(file.toRealPath(), copyOfAbsoluteSymlinkToFile.toRealPath());
327 }
328
329 @Test
330 void testCopyDirectoryWithNoFollowLinksPreservesCyclicSymbolicLink() throws Exception {
331 final Path sourceDir = Files.createDirectory(tempDirPath.resolve("source"));
332 final Path dir1 = Files.createDirectory(sourceDir.resolve("dir1"));
333 final Path dir2 = Files.createDirectory(dir1.resolve("dir2"));
334 Files.createSymbolicLink(dir2.resolve("cyclic-symlink"), dir2.relativize(dir1));
335 final Path targetDir = tempDirPath.resolve("target");
336 PathUtils.copyDirectory(sourceDir, targetDir, LinkOption.NOFOLLOW_LINKS);
337 assertTrue(Files.exists(targetDir));
338 final Path copyOfDir1 = targetDir.resolve("dir1");
339 final Path copyOfDir2 = copyOfDir1.resolve("dir2");
340 assertTrue(Files.exists(copyOfDir2));
341 assertTrue(Files.isDirectory(copyOfDir2));
342 final Path copyOfCyclicSymlink = copyOfDir2.resolve("cyclic-symlink");
343 assertTrue(Files.exists(copyOfCyclicSymlink));
344 assertEquals(copyOfDir1.toRealPath(), copyOfCyclicSymlink.toRealPath());
345 }
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367 @Test
368 void testCopyDirectoryWithNoFollowLinksPreservesRelativeSymbolicLinkToDir() throws Exception {
369
370 final Path sourceDir = Files.createDirectory(tempDirPath.resolve("source"));
371 final Path dir1 = Files.createDirectory(sourceDir.resolve("dir1"));
372 final Path dir2 = Files.createDirectory(sourceDir.resolve("dir2"));
373
374 Files.createSymbolicLink(dir1.resolve("symlink"), dir1.relativize(dir2));
375 final Path targetDir = tempDirPath.resolve("target");
376
377 final PathCounters pathCounters = PathUtils.copyDirectory(sourceDir, targetDir, LinkOption.NOFOLLOW_LINKS);
378
379
380 assertEquals(3L, pathCounters.getDirectoryCounter().get());
381
382 assertEquals(1L, pathCounters.getFileCounter().get());
383 final Path copyOfDir2 = targetDir.resolve("dir2");
384 final Path copyOfRelativeSymlinkToDir2 = targetDir.resolve("dir1").resolve("symlink");
385 assertTrue(Files.isSymbolicLink(copyOfRelativeSymlinkToDir2));
386 assertTrue(Files.isDirectory(copyOfRelativeSymlinkToDir2));
387
388 assertEquals(copyOfDir2.toRealPath(), copyOfRelativeSymlinkToDir2.toRealPath());
389 }
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411 @Test
412 void testCopyDirectoryWithNoFollowLinksPreservesRelativeSymbolicLinkToFile() throws Exception {
413
414 final Path sourceDir = Files.createDirectory(tempDirPath.resolve("source"));
415 final Path dir = Files.createDirectory(sourceDir.resolve("dir"));
416 final Path file = Files.write(sourceDir.resolve("file"), PathUtilsTest.BYTE_ARRAY_FIXTURE);
417
418 Files.createSymbolicLink(dir.resolve("symlink"), dir.relativize(file));
419 final Path targetDir = tempDirPath.resolve("target");
420
421 final PathCounters pathCounters = PathUtils.copyDirectory(sourceDir, targetDir, LinkOption.NOFOLLOW_LINKS);
422
423
424 assertEquals(2L, pathCounters.getDirectoryCounter().get());
425
426 assertEquals(2L, pathCounters.getFileCounter().get());
427 final Path copyOfFile = targetDir.resolve("file");
428 final Path copyOfRelativeSymlinkToFile = targetDir.resolve("dir").resolve("symlink");
429 assertTrue(Files.isSymbolicLink(copyOfRelativeSymlinkToFile));
430 assertTrue(Files.isRegularFile(copyOfRelativeSymlinkToFile));
431
432 assertEquals(copyOfFile.toRealPath(), copyOfRelativeSymlinkToFile.toRealPath());
433 }
434
435 @Test
436 void testCopyFile() throws IOException {
437 final Path sourceFile = Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-1/file-size-1.bin");
438 final Path targetFile = PathUtils.copyFileToDirectory(sourceFile, tempDirPath);
439 assertTrue(Files.exists(targetFile));
440 assertEquals(Files.size(sourceFile), Files.size(targetFile));
441 }
442
443 @Test
444 void testCopyFileTwoFileSystem() throws IOException {
445 try (FileSystem archive = openArchive(Paths.get(TEST_JAR_PATH), false)) {
446 final Path sourceFile = archive.getPath("next/dir/test.log");
447 final Path targetFile = PathUtils.copyFileToDirectory(sourceFile, tempDirPath);
448 assertTrue(Files.exists(targetFile));
449 assertEquals(Files.size(sourceFile), Files.size(targetFile));
450 }
451 }
452
453 @Test
454 void testCopyURL() throws IOException {
455 final Path sourceFile = Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-1/file-size-1.bin");
456 final URL url = new URL("file:///" + FilenameUtils.getPath(sourceFile.toAbsolutePath().toString()) + sourceFile.getFileName());
457 final Path targetFile = PathUtils.copyFileToDirectory(url, tempDirPath);
458 assertTrue(Files.exists(targetFile));
459 assertEquals(Files.size(sourceFile), Files.size(targetFile));
460 }
461 }