1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.codehaus.plexus.archiver.tar;
25
26 import java.io.BufferedInputStream;
27 import java.io.File;
28 import java.io.IOException;
29 import java.io.Writer;
30 import java.nio.charset.StandardCharsets;
31 import java.nio.file.Files;
32 import java.util.Enumeration;
33 import java.util.LinkedHashMap;
34 import java.util.Map;
35
36 import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
37 import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
38 import org.codehaus.plexus.archiver.Archiver;
39 import org.codehaus.plexus.archiver.ArchiverException;
40 import org.codehaus.plexus.archiver.TestSupport;
41 import org.codehaus.plexus.archiver.UnixStat;
42 import org.codehaus.plexus.archiver.bzip2.BZip2Compressor;
43 import org.codehaus.plexus.archiver.exceptions.EmptyArchiveException;
44 import org.codehaus.plexus.archiver.gzip.GZipCompressor;
45 import org.codehaus.plexus.archiver.util.ArchiveEntryUtils;
46 import org.codehaus.plexus.archiver.util.Compressor;
47 import org.codehaus.plexus.archiver.util.DefaultArchivedFileSet;
48 import org.codehaus.plexus.archiver.zip.ArchiveFileComparator;
49 import org.codehaus.plexus.components.io.attributes.PlexusIoResourceAttributeUtils;
50 import org.codehaus.plexus.components.io.attributes.PlexusIoResourceAttributes;
51 import org.codehaus.plexus.util.FileUtils;
52 import org.codehaus.plexus.util.IOUtil;
53 import org.junit.jupiter.api.Test;
54 import org.junit.jupiter.api.condition.DisabledOnOs;
55 import org.junit.jupiter.api.condition.OS;
56 import org.junit.jupiter.api.io.TempDir;
57
58 import static org.codehaus.plexus.archiver.util.Streams.bufferedInputStream;
59 import static org.codehaus.plexus.components.io.resources.ResourceFactory.createResource;
60 import static org.junit.jupiter.api.Assertions.assertEquals;
61 import static org.junit.jupiter.api.Assertions.assertNotNull;
62 import static org.junit.jupiter.api.Assertions.assertTrue;
63 import static org.junit.jupiter.api.Assertions.fail;
64
65
66
67
68 class TarArchiverTest extends TestSupport {
69 @TempDir
70 private File tempDir;
71
72 @Test
73 @DisabledOnOs(OS.WINDOWS)
74 void testCreateArchiveWithDetectedModes() throws Exception {
75
76 String[] executablePaths = {"path/to/executable", "path/to/executable.bat"};
77
78 String[] confPaths = {"path/to/etc/file", "path/to/etc/file2"};
79
80 String[] logPaths = {"path/to/logs/log.txt"};
81
82 int exeMode = 0777;
83 int confMode = 0600;
84 int logMode = 0640;
85
86 for (String executablePath : executablePaths) {
87 writeFile(tempDir, executablePath, exeMode);
88 }
89
90 for (String confPath : confPaths) {
91 writeFile(tempDir, confPath, confMode);
92 }
93
94 for (String logPath : logPaths) {
95 writeFile(tempDir, logPath, logMode);
96 }
97
98 {
99 Map attributesByPath = PlexusIoResourceAttributeUtils.getFileAttributesByPath(tempDir);
100 for (String path : executablePaths) {
101 PlexusIoResourceAttributes attrs = (PlexusIoResourceAttributes) attributesByPath.get(path);
102 if (attrs == null) {
103 attrs = (PlexusIoResourceAttributes)
104 attributesByPath.get(new File(tempDir, path).getAbsolutePath());
105 }
106
107 assertNotNull(attrs);
108 assertEquals(exeMode, attrs.getOctalMode(), "Wrong mode for: " + path);
109 }
110
111 for (String path : confPaths) {
112 PlexusIoResourceAttributes attrs = (PlexusIoResourceAttributes) attributesByPath.get(path);
113 if (attrs == null) {
114 attrs = (PlexusIoResourceAttributes)
115 attributesByPath.get(new File(tempDir, path).getAbsolutePath());
116 }
117
118 assertNotNull(attrs);
119 assertEquals(confMode, attrs.getOctalMode(), "Wrong mode for: " + path);
120 }
121
122 for (String path : logPaths) {
123 PlexusIoResourceAttributes attrs = (PlexusIoResourceAttributes) attributesByPath.get(path);
124 if (attrs == null) {
125 attrs = (PlexusIoResourceAttributes)
126 attributesByPath.get(new File(tempDir, path).getAbsolutePath());
127 }
128
129 assertNotNull(attrs);
130 assertEquals(logMode, attrs.getOctalMode(), "Wrong mode for: " + path);
131 }
132 }
133
134 File tarFile = getTestFile("target/output/tar-with-modes.tar");
135
136 TarArchiver archiver = getPosixTarArchiver();
137 archiver.setDestFile(tarFile);
138
139 archiver.addDirectory(tempDir);
140 archiver.createArchive();
141
142 assertTrue(tarFile.exists());
143
144 File tarFile2 = getTestFile("target/output/tar-with-modes-L2.tar");
145
146 archiver = getPosixTarArchiver();
147 archiver.setDestFile(tarFile2);
148
149 archiver.addArchivedFileSet(tarFile);
150 archiver.createArchive();
151
152 TarFile tf = new TarFile(tarFile2);
153
154 Map<String, TarArchiveEntry> entriesByPath = new LinkedHashMap<String, TarArchiveEntry>();
155 for (Enumeration e = tf.getEntries(); e.hasMoreElements(); ) {
156 TarArchiveEntry te = (TarArchiveEntry) e.nextElement();
157 entriesByPath.put(te.getName(), te);
158 }
159
160 for (String path : executablePaths) {
161 TarArchiveEntry te = entriesByPath.get(path);
162
163 int mode = te.getMode() & UnixStat.PERM_MASK;
164
165 assertEquals(exeMode, mode, "Wrong mode for: " + path);
166 }
167
168 for (String path : confPaths) {
169 TarArchiveEntry te = entriesByPath.get(path);
170
171 int mode = te.getMode() & UnixStat.PERM_MASK;
172
173 assertEquals(confMode, mode, "Wrong mode for: " + path);
174 }
175
176 for (String path : logPaths) {
177 TarArchiveEntry te = entriesByPath.get(path);
178
179 int mode = te.getMode() & UnixStat.PERM_MASK;
180
181 assertEquals(logMode, mode, "Wrong mode for: " + path);
182 }
183 }
184
185 @Test
186 void testCreateEmptyArchive() throws Exception {
187 TarArchiver archiver = getPosixTarArchiver();
188 archiver.setDestFile(getTestFile("target/output/empty.tar"));
189 try {
190 archiver.createArchive();
191
192 fail("Creating empty archive should throw EmptyArchiveException");
193 } catch (EmptyArchiveException ignore) {
194 }
195 }
196
197 @Test
198 void testUnicode() throws Exception {
199 File tmpDir = getTestFile("src/test/resources/utf8");
200 TarArchiver archiver = getPosixTarArchiver();
201 File tarFile = getTestFile("target/output/tar-with-longFileName.tar");
202 archiver.setDestFile(tarFile);
203 archiver.setLongfile(TarLongFileMode.posix);
204 archiver.addDirectory(tmpDir);
205 archiver.createArchive();
206 assertTrue(tarFile.exists());
207 }
208
209 private void writeFile(File dir, String fname, int mode) throws IOException, ArchiverException {
210 File file = new File(dir, fname);
211
212 if (file.getParentFile() != null) {
213 file.getParentFile().mkdirs();
214 }
215
216 try (Writer writer = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) {
217 writer.write("This is a test file.");
218 }
219
220 ArchiveEntryUtils.chmod(file, mode);
221 }
222
223 @Test
224 void testCreateArchive() throws Exception {
225 createArchive(0500, new int[] {0400, 0640, 0664});
226 createArchive(0500, new int[] {0400, 0640, 0664});
227 }
228
229 void createArchive(final int directoryMode, final int fileModes[]) throws Exception {
230 int defaultFileMode = fileModes[0];
231 int oneFileMode = fileModes[1];
232 int twoFileMode = fileModes[2];
233
234 TarArchiver archiver = getPosixTarArchiver();
235
236 archiver.setDirectoryMode(directoryMode);
237
238 archiver.setFileMode(defaultFileMode);
239
240 archiver.addDirectory(getTestFile("src/main"));
241 archiver.setFileMode(oneFileMode);
242
243 archiver.addFile(getTestFile("src/test/resources/manifests/manifest1.mf"), "one.txt");
244 archiver.addFile(getTestFile("src/test/resources/manifests/manifest2.mf"), "two.txt", twoFileMode);
245 archiver.setDestFile(getTestFile("target/output/archive.tar"));
246
247 archiver.addSymlink("link_to_test_destinaton", "../test_destination/");
248
249 archiver.createArchive();
250
251 TarArchiveInputStream tis;
252
253 tis = new TarArchiveInputStream(
254 bufferedInputStream(Files.newInputStream(archiver.getDestFile().toPath())));
255 TarArchiveEntry te;
256
257 while ((te = tis.getNextTarEntry()) != null) {
258 if (te.isDirectory()) {
259 assertEquals(
260 directoryMode,
261 te.getMode() & UnixStat.PERM_MASK,
262 "un-expected tar-entry mode for [te.name=" + te.getName() + "]");
263 } else if (te.isSymbolicLink()) {
264 assertEquals("../test_destination/", te.getLinkName());
265 assertEquals("link_to_test_destinaton", te.getName());
266 assertEquals(0640, te.getMode() & UnixStat.PERM_MASK);
267 } else {
268 if (te.getName().equals("one.txt")) {
269 assertEquals(oneFileMode, te.getMode() & UnixStat.PERM_MASK);
270 } else if (te.getName().equals("two.txt")) {
271 assertEquals(twoFileMode, te.getMode() & UnixStat.PERM_MASK);
272 } else {
273 assertEquals(
274 defaultFileMode,
275 te.getMode() & UnixStat.PERM_MASK,
276 "un-expected tar-entry mode for [te.name=" + te.getName() + "]");
277 }
278 }
279 }
280 IOUtil.close(tis);
281 }
282
283 @Test
284 void testCreateArchiveWithJiustASymlink() throws Exception {
285 TarArchiver archiver = getPosixTarArchiver();
286
287 archiver.setDirectoryMode(0500);
288
289 archiver.setFileMode(0400);
290
291 archiver.setFileMode(0640);
292
293 archiver.setDestFile(getTestFile("target/output/symlinkarchive.tar"));
294
295 archiver.addSymlink("link_to_test_destinaton", "../test_destination/");
296
297 archiver.createArchive();
298
299 TarArchiveInputStream tis;
300
301 tis = new TarArchiveInputStream(new BufferedInputStream(
302 Files.newInputStream(archiver.getDestFile().toPath())));
303 TarArchiveEntry te;
304
305 while ((te = tis.getNextTarEntry()) != null) {
306 if (te.isDirectory()) {
307 assertEquals(
308 0500,
309 te.getMode() & UnixStat.PERM_MASK,
310 "un-expected tar-entry mode for [te.name=" + te.getName() + "]");
311 } else if (te.isSymbolicLink()) {
312 assertEquals("../test_destination/", te.getLinkName());
313 assertEquals("link_to_test_destinaton", te.getName());
314 assertEquals(0640, te.getMode() & UnixStat.PERM_MASK);
315 } else {
316 assertEquals(
317 0400,
318 te.getMode() & UnixStat.PERM_MASK,
319 "un-expected tar-entry mode for [te.name=" + te.getName() + "]");
320 }
321 }
322 tis.close();
323 }
324
325 private TarArchiver getPosixTarArchiver() throws Exception {
326 TarArchiver archiver = (TarArchiver) lookup(Archiver.class, "tar");
327 archiver.setLongfile(TarLongFileMode.posix);
328 return archiver;
329 }
330
331 private class TarHandler {
332
333 File createTarFile() throws Exception {
334 final File srcDir = new File("src");
335 final File tarFile = new File("target/output/src.tar");
336 TarArchiver tarArchiver = getPosixTarArchiver();
337 tarArchiver.setDestFile(tarFile);
338 tarArchiver.addDirectory(srcDir, null, FileUtils.getDefaultExcludes());
339 FileUtils.removePath(tarFile.getPath());
340 tarArchiver.createArchive();
341 return tarFile;
342 }
343
344 File createTarfile2(File tarFile) throws Exception {
345 final File tarFile2 = new File("target/output/src2.tar");
346 TarArchiver tarArchiver2 = getPosixTarArchiver();
347 tarArchiver2.setDestFile(tarFile2);
348 tarArchiver2.addArchivedFileSet(tarFile, "prfx/");
349 FileUtils.removePath(tarFile2.getPath());
350 tarArchiver2.createArchive();
351 return tarFile2;
352 }
353
354 TarFile newTarFile(File tarFile) {
355 return new TarFile(tarFile);
356 }
357 }
358
359 private class GZipTarHandler extends TarHandler {
360
361 @Override
362 File createTarFile() throws Exception {
363 File file = super.createTarFile();
364 File compressedFile = new File(file.getPath() + ".gz");
365 Compressor compressor = new GZipCompressor();
366 compressor.setSource(createResource(file, file.getName()));
367 compressor.setDestFile(compressedFile);
368 compressor.compress();
369 compressor.close();
370 return compressedFile;
371 }
372
373 @Override
374 TarFile newTarFile(File tarFile) {
375 return new GZipTarFile(tarFile);
376 }
377 }
378
379 private class BZip2TarHandler extends TarHandler {
380
381 @Override
382 File createTarFile() throws Exception {
383 File file = super.createTarFile();
384 File compressedFile = new File(file.getPath() + ".bz2");
385 Compressor compressor = new BZip2Compressor();
386 compressor.setSource(createResource(file));
387 compressor.setDestFile(compressedFile);
388 compressor.compress();
389 compressor.close();
390 return compressedFile;
391 }
392
393 @Override
394 TarFile newTarFile(File tarFile) {
395 return new BZip2TarFile(tarFile);
396 }
397 }
398
399 @Test
400 void testUncompressedResourceCollection() throws Exception {
401 testCreateResourceCollection(new TarHandler());
402 }
403
404 @Test
405 void testGzipCompressedResourceCollection() throws Exception {
406 testCreateResourceCollection(new GZipTarHandler());
407 }
408
409 @Test
410 void testGzipFIleHandleLeak() throws Exception {
411 GZipTarHandler tarHandler = new GZipTarHandler();
412 final File tarFile = tarHandler.createTarFile();
413 final File tarFile2 = tarHandler.createTarfile2(tarFile);
414 final TarFile cmp1 = tarHandler.newTarFile(tarFile);
415 final TarFile cmp2 = new TarFile(tarFile2);
416 ArchiveFileComparator.forEachTarArchiveEntry(cmp1, ze1 -> assertNotNull(ze1.getName()));
417 cmp1.close();
418 cmp2.close();
419 }
420
421 @Test
422 void testBzip2CompressedResourceCollection() throws Exception {
423 testCreateResourceCollection(new BZip2TarHandler());
424 }
425
426 @Test
427 void testTarFileNotClosingInputStream() throws Exception {
428
429 TarHandler tarHandler = new BZip2TarHandler();
430 final File fileName = tarHandler.createTarFile();
431 final TarFile tarFile = tarHandler.newTarFile(fileName);
432 tarFile.getEntries();
433 tarFile.close();
434 }
435
436 private void testCreateResourceCollection(TarHandler tarHandler) throws Exception {
437 final File tarFile = tarHandler.createTarFile();
438 final File tarFile2 = tarHandler.createTarfile2(tarFile);
439 final TarFile cmp1 = tarHandler.newTarFile(tarFile);
440 final TarFile cmp2 = new TarFile(tarFile2);
441 ArchiveFileComparator.assertTarEquals(cmp1, cmp2, "prfx/");
442 cmp1.close();
443 cmp2.close();
444 }
445
446 @Test
447 void testSymlinkArchivedFileSet() throws Exception {
448 final File tarFile = getTestFile("src/test/resources/symlinks/symlinks.tar");
449 final File tarFile2 = getTestFile("target/output/pasymlinks-archivedFileset.tar");
450 final TarArchiver tarArchiver = getPosixTarArchiver();
451 tarArchiver.setDestFile(tarFile2);
452 DefaultArchivedFileSet archivedFileSet =
453 DefaultArchivedFileSet.archivedFileSet(tarFile).usingDefaultExcludes(false);
454 tarArchiver.addArchivedFileSet(archivedFileSet);
455 tarArchiver.createArchive();
456
457 final TarFile cmp1 = new TarFile(tarFile);
458 final TarFile cmp2 = new TarFile(tarFile2);
459 ArchiveFileComparator.assertTarEquals(cmp1, cmp2, "");
460 }
461 }