| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * https://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.commons.compress.archivers; |
| |
| import static java.nio.charset.StandardCharsets.UTF_8; |
| import static org.junit.jupiter.api.Assertions.assertArrayEquals; |
| import static org.junit.jupiter.api.Assertions.assertEquals; |
| import static org.junit.jupiter.api.Assertions.assertFalse; |
| import static org.junit.jupiter.api.Assertions.assertInstanceOf; |
| import static org.junit.jupiter.api.Assertions.assertNotNull; |
| import static org.junit.jupiter.api.Assertions.assertThrows; |
| import static org.junit.jupiter.api.Assertions.assertTrue; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.nio.charset.StandardCharsets; |
| import java.nio.file.Files; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| import org.apache.commons.compress.AbstractTest; |
| import org.apache.commons.compress.archivers.tar.TarArchiveEntry; |
| import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; |
| import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; |
| import org.apache.commons.compress.archivers.tar.TarConstants; |
| import org.apache.commons.compress.archivers.tar.TarFile; |
| import org.apache.commons.io.IOUtils; |
| import org.apache.commons.lang3.ArrayUtils; |
| import org.junit.jupiter.api.Test; |
| |
| import shaded.org.apache.commons.lang3.StringUtils; |
| |
| public final class TarTest extends AbstractTest { |
| |
| private String createLongName(final int nameLength) { |
| return StringUtils.repeat('a', nameLength); |
| } |
| |
| private byte[] createTarWithOneLongNameEntry(final String longName) throws IOException { |
| final ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
| try (TarArchiveOutputStream tos = new TarArchiveOutputStream(bos)) { |
| tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU); |
| final TarArchiveEntry longFileNameEntry = new TarArchiveEntry(longName); |
| tos.putArchiveEntry(longFileNameEntry); |
| tos.closeArchiveEntry(); |
| } |
| return bos.toByteArray(); |
| } |
| |
| @Test |
| void testCOMPRESS114() throws Exception { |
| try (TarArchiveInputStream in = TarArchiveInputStream.builder() |
| .setURI(getURI("COMPRESS-114.tar")) |
| .setCharset(StandardCharsets.ISO_8859_1) |
| .get()) { |
| TarArchiveEntry entry = in.getNextEntry(); |
| assertEquals("3\u00b1\u00b1\u00b1F06\u00b1W2345\u00b1ZB\u00b1la\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1BLA", entry.getName()); |
| assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag()); |
| entry = in.getNextEntry(); |
| assertEquals("0302-0601-3\u00b1\u00b1\u00b1F06\u00b1W2345\u00b1ZB\u00b1la\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1BLA", entry.getName()); |
| assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag()); |
| } |
| } |
| |
| @Test |
| void testCOMPRESS178() throws Exception { |
| final File input = getFile("COMPRESS-178-fail.tar"); |
| try (InputStream is = Files.newInputStream(input.toPath()); |
| ArchiveInputStream<?> in = ArchiveStreamFactory.DEFAULT.createArchiveInputStream("tar", is)) { |
| final IOException e = assertThrows(ArchiveException.class, in::getNextEntry, "Expected IOException"); |
| final Throwable t = e.getCause(); |
| assertInstanceOf(IllegalArgumentException.class, t, "Expected cause = IllegalArgumentException"); |
| } |
| } |
| |
| @Test |
| void testCOMPRESS178Lenient() throws Exception { |
| try (ArchiveInputStream<?> in = TarArchiveInputStream.builder() |
| .setURI(getURI("COMPRESS-178-fail.tar")) |
| .setLenient(true) |
| .get()) { |
| in.getNextEntry(); |
| } |
| } |
| |
| @Test |
| void testDirectoryEntryFromFile() throws Exception { |
| final File archive = createTempFile("test.", ".tar"); |
| final long beforeArchiveWrite; |
| try (TarArchiveOutputStream tos = new TarArchiveOutputStream(Files.newOutputStream(archive.toPath()))) { |
| final File dir = getTempDirFile(); |
| beforeArchiveWrite = dir.lastModified(); |
| final TarArchiveEntry in = new TarArchiveEntry(dir, "foo"); |
| tos.putArchiveEntry(in); |
| tos.closeArchiveEntry(); |
| } |
| final TarArchiveEntry out; |
| try (TarArchiveInputStream tis = TarArchiveInputStream.builder().setFile(archive).get()) { |
| out = tis.getNextTarEntry(); |
| } |
| assertNotNull(out); |
| assertEquals("foo/", out.getName()); |
| assertEquals(TarConstants.LF_DIR, out.getLinkFlag()); |
| assertEquals(0, out.getSize()); |
| // TAR stores time with a granularity of 1 second |
| assertEquals(beforeArchiveWrite / 1000, out.getLastModifiedDate().getTime() / 1000); |
| assertTrue(out.isDirectory()); |
| } |
| |
| @Test |
| void testDirectoryRead() throws IOException { |
| try (TarArchiveInputStream in = |
| TarArchiveInputStream.builder().setURI(getURI("directory.tar")).get()) { |
| final TarArchiveEntry directoryEntry = in.getNextTarEntry(); |
| assertEquals("directory/", directoryEntry.getName()); |
| assertEquals(TarConstants.LF_DIR, directoryEntry.getLinkFlag()); |
| assertTrue(directoryEntry.isDirectory()); |
| final byte[] directoryRead = IOUtils.toByteArray(in); |
| assertArrayEquals(ArrayUtils.EMPTY_BYTE_ARRAY, directoryRead); |
| } |
| } |
| |
| @Test |
| void testExplicitDirectoryEntry() throws Exception { |
| final File archive = createTempFile("test.", ".tar"); |
| final long beforeArchiveWrite; |
| final TarArchiveEntry in = new TarArchiveEntry("foo/"); |
| try (TarArchiveOutputStream tos = new TarArchiveOutputStream(Files.newOutputStream(archive.toPath()))) { |
| beforeArchiveWrite = getTempDirFile().lastModified(); |
| in.setModTime(beforeArchiveWrite); |
| tos.putArchiveEntry(in); |
| tos.closeArchiveEntry(); |
| } |
| final TarArchiveEntry out; |
| try (TarArchiveInputStream tis = TarArchiveInputStream.builder().setFile(archive).get()) { |
| out = tis.getNextTarEntry(); |
| } |
| assertNotNull(out); |
| assertEquals("foo/", out.getName()); |
| assertEquals(TarConstants.LF_DIR, in.getLinkFlag()); |
| assertEquals(0, out.getSize()); |
| assertEquals(beforeArchiveWrite / 1000, out.getLastModifiedDate().getTime() / 1000); |
| assertTrue(out.isDirectory()); |
| } |
| |
| @Test |
| void testExplicitFileEntry() throws Exception { |
| final File file = createTempFile(); |
| final File archive = createTempFile("test.", ".tar"); |
| try (TarArchiveOutputStream outputStream = new TarArchiveOutputStream(Files.newOutputStream(archive.toPath()))) { |
| final TarArchiveEntry entryIn = new TarArchiveEntry("foo"); |
| entryIn.setModTime(file.lastModified()); |
| entryIn.setSize(file.length()); |
| outputStream.putArchiveEntry(entryIn); |
| outputStream.write(file); |
| outputStream.closeArchiveEntry(); |
| } |
| final TarArchiveEntry entryOut; |
| try (TarArchiveInputStream tis = TarArchiveInputStream.builder().setFile(archive).get()) { |
| entryOut = tis.getNextTarEntry(); |
| } |
| assertNotNull(entryOut); |
| assertEquals("foo", entryOut.getName()); |
| assertEquals(TarConstants.LF_NORMAL, entryOut.getLinkFlag()); |
| assertEquals(file.length(), entryOut.getSize()); |
| assertEquals(file.lastModified() / 1000, entryOut.getLastModifiedDate().getTime() / 1000); |
| assertFalse(entryOut.isDirectory()); |
| } |
| |
| @Test |
| void testFileEntryFromFile() throws Exception { |
| final File file = createTempFile(); |
| final File archive = createTempFile("test.", ".tar"); |
| final TarArchiveEntry in = new TarArchiveEntry(file, "foo"); |
| try (TarArchiveOutputStream outputStream = new TarArchiveOutputStream(Files.newOutputStream(archive.toPath()))) { |
| outputStream.putArchiveEntry(in); |
| outputStream.write(file); |
| outputStream.closeArchiveEntry(); |
| } |
| final TarArchiveEntry out; |
| try (TarArchiveInputStream tis = TarArchiveInputStream.builder().setFile(archive).get()) { |
| out = tis.getNextTarEntry(); |
| } |
| assertNotNull(out); |
| assertEquals("foo", out.getName()); |
| assertEquals(TarConstants.LF_NORMAL, out.getLinkFlag()); |
| assertEquals(file.length(), out.getSize()); |
| assertEquals(file.lastModified() / 1000, out.getLastModifiedDate().getTime() / 1000); |
| assertFalse(out.isDirectory()); |
| } |
| |
| @Test |
| void testLongNameLargerThanBuffer() throws IOException { |
| final List<Integer> nameLength = Arrays.asList(300, 4096); |
| |
| for (final Integer length : nameLength) { |
| final String fileName = createLongName(length); |
| assertEquals(length.intValue(), fileName.length()); |
| final byte[] data = createTarWithOneLongNameEntry(fileName); |
| try (TarArchiveInputStream tis = |
| TarArchiveInputStream.builder().setByteArray(data).get()) { |
| assertEquals(fileName, tis.getNextTarEntry().getName()); |
| } |
| } |
| } |
| |
| @Test |
| void testTarArchiveCreation() throws Exception { |
| final File output = newTempFile("bla.tar"); |
| final File file1 = getFile("test1.xml"); |
| try (OutputStream out = Files.newOutputStream(output.toPath()); |
| TarArchiveOutputStream os = ArchiveStreamFactory.DEFAULT.createArchiveOutputStream("tar", out)) { |
| final TarArchiveEntry entry = new TarArchiveEntry("testdata/test1.xml"); |
| entry.setModTime(0); |
| entry.setSize(file1.length()); |
| entry.setUserId(0); |
| entry.setGroupId(0); |
| entry.setUserName("avalon"); |
| entry.setGroupName("excalibur"); |
| entry.setMode(0100000); |
| os.putArchiveEntry(entry); |
| os.write(file1); |
| os.closeArchiveEntry(); |
| } |
| } |
| |
| @Test |
| void testTarArchiveLongNameCreation() throws Exception { |
| final String name = "testdata/12345678901234567890123456789012345678901234567890123456789012345678901234567890123456.xml"; |
| final byte[] bytes = name.getBytes(UTF_8); |
| assertEquals(bytes.length, 99); |
| |
| final File output = newTempFile("bla.tar"); |
| final File file1 = getFile("test1.xml"); |
| final TarArchiveEntry entry = new TarArchiveEntry(name); |
| try (OutputStream out = Files.newOutputStream(output.toPath()); |
| TarArchiveOutputStream os = ArchiveStreamFactory.DEFAULT.createArchiveOutputStream("tar", out)) { |
| entry.setModTime(0); |
| entry.setSize(file1.length()); |
| entry.setUserId(0); |
| entry.setGroupId(0); |
| entry.setUserName("avalon"); |
| entry.setGroupName("excalibur"); |
| entry.setMode(0100000); |
| os.putArchiveEntry(entry); |
| os.write(file1); |
| os.closeArchiveEntry(); |
| } |
| |
| final String toLongName = "testdata/123456789012345678901234567890123456789012345678901234567890123456789012345678901234567.xml"; |
| final File output2 = newTempFile("bla.tar"); |
| try (OutputStream out2 = Files.newOutputStream(output2.toPath()); |
| TarArchiveOutputStream os2 = ArchiveStreamFactory.DEFAULT.createArchiveOutputStream("tar", out2);) { |
| final TarArchiveEntry entry2 = new TarArchiveEntry(toLongName); |
| entry2.setModTime(0); |
| entry2.setSize(file1.length()); |
| entry2.setUserId(0); |
| entry2.setGroupId(0); |
| entry2.setUserName("avalon"); |
| entry2.setGroupName("excalibur"); |
| entry2.setMode(0100000); |
| os2.putArchiveEntry(entry); |
| os2.write(file1); |
| os2.closeArchiveEntry(); |
| } catch (final IOException e) { |
| assertTrue(true); |
| } |
| } |
| |
| @Test |
| void testTarFileCOMPRESS114() throws Exception { |
| final File input = getFile("COMPRESS-114.tar"); |
| try (TarFile tarFile = TarFile.builder().setURI(getURI("COMPRESS-114.tar")).setCharset(StandardCharsets.ISO_8859_1).get()) { |
| final List<TarArchiveEntry> entries = tarFile.getEntries(); |
| TarArchiveEntry entry = entries.get(0); |
| assertEquals("3\u00b1\u00b1\u00b1F06\u00b1W2345\u00b1ZB\u00b1la\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1BLA", entry.getName()); |
| assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag()); |
| entry = entries.get(1); |
| assertEquals("0302-0601-3\u00b1\u00b1\u00b1F06\u00b1W2345\u00b1ZB\u00b1la\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1BLA", entry.getName()); |
| assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag()); |
| } |
| } |
| |
| @Test |
| void testTarFileCOMPRESS178() throws Exception { |
| final File input = getFile("COMPRESS-178-fail.tar"); |
| final IOException e = assertThrows(ArchiveException.class, () -> { |
| try (TarFile tarFile = TarFile.builder().setFile(input).get()) { |
| // Compared to the TarArchiveInputStream all entries are read when instantiating the tar file |
| } |
| }, "Expected IOException"); |
| final Throwable t = e.getCause(); |
| assertInstanceOf(IllegalArgumentException.class, t, "Expected cause = IllegalArgumentException"); |
| } |
| |
| @Test |
| void testTarFileCOMPRESS178Lenient() throws Exception { |
| final File input = getFile("COMPRESS-178-fail.tar"); |
| try (TarFile tarFile = TarFile.builder().setFile(input).setLenient(true).get()) { |
| // Compared to the TarArchiveInputStream all entries are read when instantiating the tar file |
| } |
| } |
| |
| @Test |
| void testTarFileDirectoryEntryFromFile() throws Exception { |
| final File archive = createTempFile("test.", ".tar"); |
| final File dir = getTempDirFile(); |
| try (TarArchiveOutputStream tos = new TarArchiveOutputStream(Files.newOutputStream(archive.toPath()))) { |
| final long beforeArchiveWrite = dir.lastModified(); |
| final TarArchiveEntry in = new TarArchiveEntry(dir, "foo"); |
| tos.putArchiveEntry(in); |
| tos.closeArchiveEntry(); |
| tos.close(); |
| try (TarFile tarFile = TarFile.builder().setFile(archive).get()) { |
| final TarArchiveEntry entry = tarFile.getEntries().get(0); |
| assertNotNull(entry); |
| assertEquals("foo/", entry.getName()); |
| assertEquals(TarConstants.LF_DIR, entry.getLinkFlag()); |
| assertEquals(0, entry.getSize()); |
| // TAR stores time with a granularity of 1 second |
| assertEquals(beforeArchiveWrite / 1000, entry.getLastModifiedDate().getTime() / 1000); |
| assertTrue(entry.isDirectory()); |
| } |
| } |
| } |
| |
| @Test |
| void testTarFileDirectoryRead() throws IOException { |
| final File input = getFile("directory.tar"); |
| try (TarFile tarFile = TarFile.builder().setFile(input).get()) { |
| final TarArchiveEntry directoryEntry = tarFile.getEntries().get(0); |
| assertEquals("directory/", directoryEntry.getName()); |
| assertEquals(TarConstants.LF_DIR, directoryEntry.getLinkFlag()); |
| assertTrue(directoryEntry.isDirectory()); |
| try (InputStream directoryStream = tarFile.getInputStream(directoryEntry)) { |
| final byte[] directoryRead = IOUtils.toByteArray(directoryStream); |
| assertArrayEquals(ArrayUtils.EMPTY_BYTE_ARRAY, directoryRead); |
| } |
| } |
| } |
| |
| @Test |
| void testTarFileEntryFromFile() throws Exception { |
| final File file = createTempFile(); |
| final File archive = createTempFile("test.", ".tar"); |
| try (TarArchiveOutputStream outputStream = new TarArchiveOutputStream(Files.newOutputStream(archive.toPath()))) { |
| final TarArchiveEntry in = new TarArchiveEntry(file, "foo"); |
| outputStream.putArchiveEntry(in); |
| outputStream.write(file); |
| outputStream.closeArchiveEntry(); |
| outputStream.close(); |
| try (TarFile tarFile = TarFile.builder().setFile(archive).get()) { |
| final TarArchiveEntry entry = tarFile.getEntries().get(0); |
| assertNotNull(entry); |
| assertEquals("foo", entry.getName()); |
| assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag()); |
| assertEquals(file.length(), entry.getSize()); |
| assertEquals(file.lastModified() / 1000, entry.getLastModifiedDate().getTime() / 1000); |
| assertFalse(entry.isDirectory()); |
| } |
| } |
| } |
| |
| @Test |
| void testTarFileExplicitDirectoryEntry() throws Exception { |
| final File archive = createTempFile("test.", ".tar"); |
| try (TarArchiveOutputStream tos = new TarArchiveOutputStream(Files.newOutputStream(archive.toPath()))) { |
| final long beforeArchiveWrite = getTempDirFile().lastModified(); |
| final TarArchiveEntry in = new TarArchiveEntry("foo/"); |
| in.setModTime(beforeArchiveWrite); |
| tos.putArchiveEntry(in); |
| tos.closeArchiveEntry(); |
| tos.close(); |
| try (TarFile tarFile = TarFile.builder().setFile(archive).get()) { |
| final TarArchiveEntry entry = tarFile.getEntries().get(0); |
| assertNotNull(entry); |
| assertEquals("foo/", entry.getName()); |
| assertEquals(TarConstants.LF_DIR, entry.getLinkFlag()); |
| assertEquals(0, entry.getSize()); |
| assertEquals(beforeArchiveWrite / 1000, entry.getLastModifiedDate().getTime() / 1000); |
| assertTrue(entry.isDirectory()); |
| } |
| } |
| } |
| |
| @Test |
| void testTarFileExplicitFileEntry() throws Exception { |
| final File file = createTempFile(); |
| final File archive = createTempFile("test.", ".tar"); |
| try (TarArchiveOutputStream outputStream = new TarArchiveOutputStream(Files.newOutputStream(archive.toPath()))) { |
| final TarArchiveEntry in = new TarArchiveEntry("foo"); |
| in.setModTime(file.lastModified()); |
| in.setSize(file.length()); |
| outputStream.putArchiveEntry(in); |
| outputStream.write(file); |
| outputStream.closeArchiveEntry(); |
| try (TarFile tarFile = TarFile.builder().setFile(archive).get()) { |
| final TarArchiveEntry entry = tarFile.getEntries().get(0); |
| assertNotNull(entry); |
| assertEquals("foo", entry.getName()); |
| assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag()); |
| assertEquals(file.length(), entry.getSize()); |
| assertEquals(file.lastModified() / 1000, entry.getLastModifiedDate().getTime() / 1000); |
| assertFalse(entry.isDirectory()); |
| } |
| } |
| } |
| |
| @Test |
| void testTarFileLongNameLargerThanBuffer() throws IOException { |
| final List<Integer> nameLength = Arrays.asList(300, 4096); |
| |
| for (final Integer length : nameLength) { |
| final String fileName = createLongName(length); |
| assertEquals(length.intValue(), fileName.length()); |
| final byte[] data = createTarWithOneLongNameEntry(fileName); |
| try (TarFile tarFile = TarFile.builder().setByteArray(data).get()) { |
| final List<TarArchiveEntry> entries = tarFile.getEntries(); |
| assertEquals(fileName, entries.get(0).getName()); |
| assertEquals(TarConstants.LF_NORMAL, entries.get(0).getLinkFlag()); |
| } |
| } |
| } |
| |
| @Test |
| void testTarFileUnarchive() throws Exception { |
| final File file = getFile("bla.tar"); |
| try (TarFile tarFile = TarFile.builder().setFile(file).get()) { |
| final TarArchiveEntry entry = tarFile.getEntries().get(0); |
| try (InputStream inputStream = tarFile.getInputStream(entry)) { |
| Files.copy(inputStream, newTempFile(entry.getName()).toPath()); |
| } |
| } |
| } |
| |
| @Test |
| void testTarUnarchive() throws Exception { |
| final File input = getFile("bla.tar"); |
| try (InputStream is = Files.newInputStream(input.toPath()); |
| TarArchiveInputStream in = ArchiveStreamFactory.DEFAULT.createArchiveInputStream("tar", is)) { |
| final TarArchiveEntry entry = in.getNextEntry(); |
| Files.copy(in, newTempFile(entry.getName()).toPath()); |
| } |
| } |
| } |