1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.commons.compress.archivers;
20
21 import static java.nio.charset.StandardCharsets.UTF_8;
22 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
23 import static org.junit.jupiter.api.Assertions.assertEquals;
24 import static org.junit.jupiter.api.Assertions.assertFalse;
25 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
26 import static org.junit.jupiter.api.Assertions.assertNotNull;
27 import static org.junit.jupiter.api.Assertions.assertThrows;
28 import static org.junit.jupiter.api.Assertions.assertTrue;
29
30 import java.io.ByteArrayInputStream;
31 import java.io.ByteArrayOutputStream;
32 import java.io.File;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.OutputStream;
36 import java.nio.charset.StandardCharsets;
37 import java.nio.file.Files;
38 import java.util.Arrays;
39 import java.util.List;
40
41 import org.apache.commons.compress.AbstractTest;
42 import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
43 import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
44 import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
45 import org.apache.commons.compress.archivers.tar.TarConstants;
46 import org.apache.commons.compress.archivers.tar.TarFile;
47 import org.apache.commons.compress.utils.ByteUtils;
48 import org.apache.commons.io.IOUtils;
49 import org.junit.jupiter.api.Test;
50
51 public final class TarTest extends AbstractTest {
52
53 private String createLongName(final int nameLength) {
54 final StringBuilder buffer = new StringBuilder();
55 for (int i = 0; i < nameLength; i++) {
56 buffer.append('a');
57 }
58 return buffer.toString();
59 }
60
61 private byte[] createTarWithOneLongNameEntry(final String longName) throws IOException {
62 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
63 try (TarArchiveOutputStream tos = new TarArchiveOutputStream(bos)) {
64 tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
65 final TarArchiveEntry longFileNameEntry = new TarArchiveEntry(longName);
66 tos.putArchiveEntry(longFileNameEntry);
67 tos.closeArchiveEntry();
68 }
69 return bos.toByteArray();
70 }
71
72 @Test
73 public void testCOMPRESS114() throws Exception {
74 final File input = getFile("COMPRESS-114.tar");
75 try (InputStream is = Files.newInputStream(input.toPath());
76 TarArchiveInputStream in = new TarArchiveInputStream(is, StandardCharsets.ISO_8859_1.name())) {
77 TarArchiveEntry entry = in.getNextEntry();
78 assertEquals("3\u00b1\u00b1\u00b1F06\u00b1W2345\u00b1ZB\u00b1la\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1BLA", entry.getName());
79 assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag());
80 entry = in.getNextEntry();
81 assertEquals("0302-0601-3\u00b1\u00b1\u00b1F06\u00b1W2345\u00b1ZB\u00b1la\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1BLA", entry.getName());
82 assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag());
83 }
84 }
85
86 @Test
87 public void testCOMPRESS178() throws Exception {
88 final File input = getFile("COMPRESS-178-fail.tar");
89 try (InputStream is = Files.newInputStream(input.toPath());
90 ArchiveInputStream<?> in = ArchiveStreamFactory.DEFAULT.createArchiveInputStream("tar", is)) {
91 final IOException e = assertThrows(IOException.class, in::getNextEntry, "Expected IOException");
92 final Throwable t = e.getCause();
93 assertInstanceOf(IllegalArgumentException.class, t, "Expected cause = IllegalArgumentException");
94 }
95 }
96
97 @Test
98 public void testCOMPRESS178Lenient() throws Exception {
99 final File input = getFile("COMPRESS-178-fail.tar");
100 try (InputStream is = Files.newInputStream(input.toPath());
101 ArchiveInputStream<?> in = new TarArchiveInputStream(is, true)) {
102 in.getNextEntry();
103 }
104 }
105
106 @Test
107 public void testDirectoryEntryFromFile() throws Exception {
108 final File archive = createTempFile("test.", ".tar");
109 final long beforeArchiveWrite;
110 try (TarArchiveOutputStream tos = new TarArchiveOutputStream(Files.newOutputStream(archive.toPath()))) {
111 final File dir = getTempDirFile();
112 beforeArchiveWrite = dir.lastModified();
113 final TarArchiveEntry in = new TarArchiveEntry(dir, "foo");
114 tos.putArchiveEntry(in);
115 tos.closeArchiveEntry();
116 }
117 final TarArchiveEntry out;
118 try (TarArchiveInputStream tis = new TarArchiveInputStream(Files.newInputStream(archive.toPath()))) {
119 out = tis.getNextTarEntry();
120 }
121 assertNotNull(out);
122 assertEquals("foo/", out.getName());
123 assertEquals(TarConstants.LF_DIR, out.getLinkFlag());
124 assertEquals(0, out.getSize());
125
126 assertEquals(beforeArchiveWrite / 1000, out.getLastModifiedDate().getTime() / 1000);
127 assertTrue(out.isDirectory());
128 }
129
130 @Test
131 public void testDirectoryRead() throws IOException {
132 final File input = getFile("directory.tar");
133 try (InputStream is = Files.newInputStream(input.toPath());
134 TarArchiveInputStream in = new TarArchiveInputStream(is)) {
135 final TarArchiveEntry directoryEntry = in.getNextTarEntry();
136 assertEquals("directory/", directoryEntry.getName());
137 assertEquals(TarConstants.LF_DIR, directoryEntry.getLinkFlag());
138 assertTrue(directoryEntry.isDirectory());
139 final byte[] directoryRead = IOUtils.toByteArray(in);
140 assertArrayEquals(ByteUtils.EMPTY_BYTE_ARRAY, directoryRead);
141 }
142 }
143
144 @Test
145 public void testExplicitDirectoryEntry() throws Exception {
146 final File archive = createTempFile("test.", ".tar");
147 final long beforeArchiveWrite;
148 final TarArchiveEntry in = new TarArchiveEntry("foo/");
149 try (TarArchiveOutputStream tos = new TarArchiveOutputStream(Files.newOutputStream(archive.toPath()))) {
150 beforeArchiveWrite = getTempDirFile().lastModified();
151 in.setModTime(beforeArchiveWrite);
152 tos.putArchiveEntry(in);
153 tos.closeArchiveEntry();
154 }
155 final TarArchiveEntry out;
156 try (TarArchiveInputStream tis = new TarArchiveInputStream(Files.newInputStream(archive.toPath()))) {
157 out = tis.getNextTarEntry();
158 }
159 assertNotNull(out);
160 assertEquals("foo/", out.getName());
161 assertEquals(TarConstants.LF_DIR, in.getLinkFlag());
162 assertEquals(0, out.getSize());
163 assertEquals(beforeArchiveWrite / 1000, out.getLastModifiedDate().getTime() / 1000);
164 assertTrue(out.isDirectory());
165 }
166
167 @Test
168 public void testExplicitFileEntry() throws Exception {
169 final File tmp = createTempFile();
170 final File archive = createTempFile("test.", ".tar");
171 try (TarArchiveOutputStream tos = new TarArchiveOutputStream(Files.newOutputStream(archive.toPath()))) {
172 final TarArchiveEntry entryIn = new TarArchiveEntry("foo");
173 entryIn.setModTime(tmp.lastModified());
174 entryIn.setSize(tmp.length());
175 tos.putArchiveEntry(entryIn);
176 final byte[] b = new byte[(int) tmp.length()];
177 try (InputStream fis = Files.newInputStream(tmp.toPath())) {
178 while (fis.read(b) > 0) {
179 tos.write(b);
180 }
181 }
182 tos.closeArchiveEntry();
183 }
184 final TarArchiveEntry entryOut;
185 try (TarArchiveInputStream tis = new TarArchiveInputStream(Files.newInputStream(archive.toPath()))) {
186 entryOut = tis.getNextTarEntry();
187 }
188 assertNotNull(entryOut);
189 assertEquals("foo", entryOut.getName());
190 assertEquals(TarConstants.LF_NORMAL, entryOut.getLinkFlag());
191 assertEquals(tmp.length(), entryOut.getSize());
192 assertEquals(tmp.lastModified() / 1000, entryOut.getLastModifiedDate().getTime() / 1000);
193 assertFalse(entryOut.isDirectory());
194 }
195
196 @Test
197 public void testFileEntryFromFile() throws Exception {
198 final File tmp = createTempFile();
199 final File archive = createTempFile("test.", ".tar");
200 final TarArchiveEntry in = new TarArchiveEntry(tmp, "foo");
201 try (TarArchiveOutputStream tos = new TarArchiveOutputStream(Files.newOutputStream(archive.toPath()))) {
202 tos.putArchiveEntry(in);
203 final byte[] b = new byte[(int) tmp.length()];
204 try (InputStream fis = Files.newInputStream(tmp.toPath())) {
205 while (fis.read(b) > 0) {
206 tos.write(b);
207 }
208 }
209 tos.closeArchiveEntry();
210 }
211 final TarArchiveEntry out;
212 try (TarArchiveInputStream tis = new TarArchiveInputStream(Files.newInputStream(archive.toPath()))) {
213 out = tis.getNextTarEntry();
214 }
215 assertNotNull(out);
216 assertEquals("foo", out.getName());
217 assertEquals(TarConstants.LF_NORMAL, out.getLinkFlag());
218 assertEquals(tmp.length(), out.getSize());
219 assertEquals(tmp.lastModified() / 1000, out.getLastModifiedDate().getTime() / 1000);
220 assertFalse(out.isDirectory());
221 }
222
223 @Test
224 public void testLongNameLargerThanBuffer() throws IOException {
225 final List<Integer> nameLength = Arrays.asList(300, 4096);
226
227 for (final Integer length : nameLength) {
228 final String fileName = createLongName(length);
229 assertEquals(length.intValue(), fileName.length());
230 final byte[] data = createTarWithOneLongNameEntry(fileName);
231 try (ByteArrayInputStream bis = new ByteArrayInputStream(data);
232 TarArchiveInputStream tis = new TarArchiveInputStream(bis)) {
233 assertEquals(fileName, tis.getNextTarEntry().getName());
234 }
235 }
236 }
237
238 @Test
239 public void testTarArchiveCreation() throws Exception {
240 final File output = newTempFile("bla.tar");
241 final File file1 = getFile("test1.xml");
242 try (OutputStream out = Files.newOutputStream(output.toPath());
243 TarArchiveOutputStream os = ArchiveStreamFactory.DEFAULT.createArchiveOutputStream("tar", out)) {
244 final TarArchiveEntry entry = new TarArchiveEntry("testdata/test1.xml");
245 entry.setModTime(0);
246 entry.setSize(file1.length());
247 entry.setUserId(0);
248 entry.setGroupId(0);
249 entry.setUserName("avalon");
250 entry.setGroupName("excalibur");
251 entry.setMode(0100000);
252 os.putArchiveEntry(entry);
253 Files.copy(file1.toPath(), os);
254 os.closeArchiveEntry();
255 }
256 }
257
258 @Test
259 public void testTarArchiveLongNameCreation() throws Exception {
260 final String name = "testdata/12345678901234567890123456789012345678901234567890123456789012345678901234567890123456.xml";
261 final byte[] bytes = name.getBytes(UTF_8);
262 assertEquals(bytes.length, 99);
263
264 final File output = newTempFile("bla.tar");
265 final File file1 = getFile("test1.xml");
266 final TarArchiveEntry entry = new TarArchiveEntry(name);
267 try (OutputStream out = Files.newOutputStream(output.toPath());
268 TarArchiveOutputStream os = ArchiveStreamFactory.DEFAULT.createArchiveOutputStream("tar", out)) {
269 entry.setModTime(0);
270 entry.setSize(file1.length());
271 entry.setUserId(0);
272 entry.setGroupId(0);
273 entry.setUserName("avalon");
274 entry.setGroupName("excalibur");
275 entry.setMode(0100000);
276 os.putArchiveEntry(entry);
277 Files.copy(file1.toPath(), os);
278 os.closeArchiveEntry();
279 }
280
281 final String toLongName = "testdata/123456789012345678901234567890123456789012345678901234567890123456789012345678901234567.xml";
282 final File output2 = newTempFile("bla.tar");
283 try (OutputStream out2 = Files.newOutputStream(output2.toPath());
284 TarArchiveOutputStream os2 = ArchiveStreamFactory.DEFAULT.createArchiveOutputStream("tar", out2);) {
285 final TarArchiveEntry entry2 = new TarArchiveEntry(toLongName);
286 entry2.setModTime(0);
287 entry2.setSize(file1.length());
288 entry2.setUserId(0);
289 entry2.setGroupId(0);
290 entry2.setUserName("avalon");
291 entry2.setGroupName("excalibur");
292 entry2.setMode(0100000);
293 os2.putArchiveEntry(entry);
294 Files.copy(file1.toPath(), os2);
295 os2.closeArchiveEntry();
296 } catch (final IOException e) {
297 assertTrue(true);
298 }
299 }
300
301 @Test
302 public void testTarFileCOMPRESS114() throws Exception {
303 final File input = getFile("COMPRESS-114.tar");
304 try (TarFile tarFile = new TarFile(input, StandardCharsets.ISO_8859_1.name())) {
305 final List<TarArchiveEntry> entries = tarFile.getEntries();
306 TarArchiveEntry entry = entries.get(0);
307 assertEquals("3\u00b1\u00b1\u00b1F06\u00b1W2345\u00b1ZB\u00b1la\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1BLA", entry.getName());
308 assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag());
309 entry = entries.get(1);
310 assertEquals("0302-0601-3\u00b1\u00b1\u00b1F06\u00b1W2345\u00b1ZB\u00b1la\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1BLA", entry.getName());
311 assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag());
312 }
313 }
314
315 @Test
316 public void testTarFileCOMPRESS178() throws Exception {
317 final File input = getFile("COMPRESS-178-fail.tar");
318 final IOException e = assertThrows(IOException.class, () -> {
319 try (TarFile tarFile = new TarFile(input)) {
320
321 }
322 }, "Expected IOException");
323 final Throwable t = e.getCause();
324 assertInstanceOf(IllegalArgumentException.class, t, "Expected cause = IllegalArgumentException");
325 }
326
327 @Test
328 public void testTarFileCOMPRESS178Lenient() throws Exception {
329 final File input = getFile("COMPRESS-178-fail.tar");
330 try (TarFile tarFile = new TarFile(input, true)) {
331
332 }
333 }
334
335 @Test
336 public void testTarFileDirectoryEntryFromFile() throws Exception {
337 final File archive = createTempFile("test.", ".tar");
338 final File dir = getTempDirFile();
339 try (TarArchiveOutputStream tos = new TarArchiveOutputStream(Files.newOutputStream(archive.toPath()))) {
340 final long beforeArchiveWrite = dir.lastModified();
341 final TarArchiveEntry in = new TarArchiveEntry(dir, "foo");
342 tos.putArchiveEntry(in);
343 tos.closeArchiveEntry();
344 tos.close();
345 try (TarFile tarFile = new TarFile(archive)) {
346 final TarArchiveEntry entry = tarFile.getEntries().get(0);
347 assertNotNull(entry);
348 assertEquals("foo/", entry.getName());
349 assertEquals(TarConstants.LF_DIR, entry.getLinkFlag());
350 assertEquals(0, entry.getSize());
351
352 assertEquals(beforeArchiveWrite / 1000, entry.getLastModifiedDate().getTime() / 1000);
353 assertTrue(entry.isDirectory());
354 }
355 }
356 }
357
358 @Test
359 public void testTarFileDirectoryRead() throws IOException {
360 final File input = getFile("directory.tar");
361 try (TarFile tarFile = new TarFile(input)) {
362 final TarArchiveEntry directoryEntry = tarFile.getEntries().get(0);
363 assertEquals("directory/", directoryEntry.getName());
364 assertEquals(TarConstants.LF_DIR, directoryEntry.getLinkFlag());
365 assertTrue(directoryEntry.isDirectory());
366 try (InputStream directoryStream = tarFile.getInputStream(directoryEntry)) {
367 final byte[] directoryRead = IOUtils.toByteArray(directoryStream);
368 assertArrayEquals(ByteUtils.EMPTY_BYTE_ARRAY, directoryRead);
369 }
370 }
371 }
372
373 @Test
374 public void testTarFileEntryFromFile() throws Exception {
375 final File tmp = createTempFile();
376 final File archive = createTempFile("test.", ".tar");
377 try (TarArchiveOutputStream tos = new TarArchiveOutputStream(Files.newOutputStream(archive.toPath()))) {
378 final TarArchiveEntry in = new TarArchiveEntry(tmp, "foo");
379 tos.putArchiveEntry(in);
380 final byte[] b = new byte[(int) tmp.length()];
381 try (InputStream fis = Files.newInputStream(tmp.toPath())) {
382 while (fis.read(b) > 0) {
383 tos.write(b);
384 }
385 }
386 tos.closeArchiveEntry();
387 tos.close();
388 try (TarFile tarFile = new TarFile(archive)) {
389 final TarArchiveEntry entry = tarFile.getEntries().get(0);
390 assertNotNull(entry);
391 assertEquals("foo", entry.getName());
392 assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag());
393 assertEquals(tmp.length(), entry.getSize());
394 assertEquals(tmp.lastModified() / 1000, entry.getLastModifiedDate().getTime() / 1000);
395 assertFalse(entry.isDirectory());
396 }
397 }
398 }
399
400 @Test
401 public void testTarFileExplicitDirectoryEntry() throws Exception {
402 final File archive = createTempFile("test.", ".tar");
403 try (TarArchiveOutputStream tos = new TarArchiveOutputStream(Files.newOutputStream(archive.toPath()))) {
404 final long beforeArchiveWrite = getTempDirFile().lastModified();
405 final TarArchiveEntry in = new TarArchiveEntry("foo/");
406 in.setModTime(beforeArchiveWrite);
407 tos.putArchiveEntry(in);
408 tos.closeArchiveEntry();
409 tos.close();
410 try (TarFile tarFile = new TarFile(archive)) {
411 final TarArchiveEntry entry = tarFile.getEntries().get(0);
412 assertNotNull(entry);
413 assertEquals("foo/", entry.getName());
414 assertEquals(TarConstants.LF_DIR, entry.getLinkFlag());
415 assertEquals(0, entry.getSize());
416 assertEquals(beforeArchiveWrite / 1000, entry.getLastModifiedDate().getTime() / 1000);
417 assertTrue(entry.isDirectory());
418 }
419 }
420 }
421
422 @Test
423 public void testTarFileExplicitFileEntry() throws Exception {
424 final File tmp = createTempFile();
425 final File archive = createTempFile("test.", ".tar");
426 try (TarArchiveOutputStream tos = new TarArchiveOutputStream(Files.newOutputStream(archive.toPath()))) {
427 final TarArchiveEntry in = new TarArchiveEntry("foo");
428 in.setModTime(tmp.lastModified());
429 in.setSize(tmp.length());
430 tos.putArchiveEntry(in);
431 final byte[] b = new byte[(int) tmp.length()];
432 try (InputStream fis = Files.newInputStream(tmp.toPath())) {
433 while (fis.read(b) > 0) {
434 tos.write(b);
435 }
436 }
437 tos.closeArchiveEntry();
438
439 try (TarFile tarFile = new TarFile(archive)) {
440 final TarArchiveEntry entry = tarFile.getEntries().get(0);
441 assertNotNull(entry);
442 assertEquals("foo", entry.getName());
443 assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag());
444 assertEquals(tmp.length(), entry.getSize());
445 assertEquals(tmp.lastModified() / 1000, entry.getLastModifiedDate().getTime() / 1000);
446 assertFalse(entry.isDirectory());
447 }
448 }
449 }
450
451 @Test
452 public void testTarFileLongNameLargerThanBuffer() throws IOException {
453 final List<Integer> nameLength = Arrays.asList(300, 4096);
454
455 for (final Integer length : nameLength) {
456 final String fileName = createLongName(length);
457 assertEquals(length.intValue(), fileName.length());
458 final byte[] data = createTarWithOneLongNameEntry(fileName);
459 try (TarFile tarFile = new TarFile(data)) {
460 final List<TarArchiveEntry> entries = tarFile.getEntries();
461 assertEquals(fileName, entries.get(0).getName());
462 assertEquals(TarConstants.LF_NORMAL, entries.get(0).getLinkFlag());
463 }
464 }
465 }
466
467 @Test
468 public void testTarFileUnarchive() throws Exception {
469 final File file = getFile("bla.tar");
470 try (TarFile tarFile = new TarFile(file)) {
471 final TarArchiveEntry entry = tarFile.getEntries().get(0);
472 try (InputStream inputStream = tarFile.getInputStream(entry)) {
473 Files.copy(inputStream, newTempFile(entry.getName()).toPath());
474 }
475 }
476 }
477
478 @Test
479 public void testTarUnarchive() throws Exception {
480 final File input = getFile("bla.tar");
481 try (InputStream is = Files.newInputStream(input.toPath());
482 TarArchiveInputStream in = ArchiveStreamFactory.DEFAULT.createArchiveInputStream("tar", is)) {
483 final TarArchiveEntry entry = in.getNextEntry();
484 Files.copy(in, newTempFile(entry.getName()).toPath());
485 }
486 }
487 }