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