[ https://issues.apache.org/jira/browse/COMPRESS-678?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17841395#comment-17841395 ]
takaaki nakama edited comment on COMPRESS-678 at 4/27/24 4:13 AM: ------------------------------------------------------------------ This is java8 compatible reproduction code. {code:java} package org.example; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import org.apache.commons.compress.archivers.ar.ArArchiveEntry; import org.apache.commons.compress.archivers.ar.ArArchiveInputStream; import org.apache.commons.compress.archivers.ar.ArArchiveOutputStream; public class Main { public static void main(String[] args) throws IOException { File file = new File("test.ar"); ArArchiveOutputStream arOut = new ArArchiveOutputStream(new FileOutputStream(file)); arOut.setLongFileMode(ArArchiveOutputStream.LONGFILE_BSD); arOut.putArchiveEntry(new ArArchiveEntry("01234567891234567", 1)); arOut.write(new byte[]{1}); arOut.closeArchiveEntry(); arOut.putArchiveEntry(new ArArchiveEntry("a", 1)); arOut.write(new byte[]{1}); arOut.closeArchiveEntry(); arOut.close(); ArArchiveInputStream arIn = new ArArchiveInputStream(new FileInputStream(file)); ArArchiveEntry entry = arIn.getNextArEntry(); System.out.println(entry.getName()); entry = arIn.getNextArEntry(); // <- This line causes the exception. System.out.println(entry.getName()); } } {code} stacktrace {code:java} Exception in thread "main" java.io.IOException: Invalid entry trailer. not read the content? Occurred at byte: 146 at org.apache.commons.compress.archivers.ar.ArArchiveInputStream.getNextArEntry(ArArchiveInputStream.java:294) at org.example.Main.main(Main.java:31) {code} was (Author: JIRAUSER305141): This is java8 compatible reproduction code. {code:java} package org.example; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import org.apache.commons.compress.archivers.ar.ArArchiveEntry; import org.apache.commons.compress.archivers.ar.ArArchiveInputStream; import org.apache.commons.compress.archivers.ar.ArArchiveOutputStream; public class Main { public static void main(String[] args) throws IOException { File file = new File("test.ar"); ArArchiveOutputStream arOut = new ArArchiveOutputStream(new FileOutputStream(file)); arOut.setLongFileMode(ArArchiveOutputStream.LONGFILE_BSD); arOut.putArchiveEntry(new ArArchiveEntry("01234567891234567", 1)); arOut.write(new byte[]{1}); arOut.closeArchiveEntry(); arOut.putArchiveEntry(new ArArchiveEntry("a", 1)); arOut.write(new byte[]{1}); arOut.closeArchiveEntry(); arOut.close(); ArArchiveInputStream arIn = new ArArchiveInputStream(new FileInputStream(file)); ArArchiveEntry entry = arIn.getNextArEntry(); System.out.println(entry.getName()); entry = arIn.getNextArEntry(); System.out.println(entry.getName()); // <- This line causes the exception. } } {code} stacktrace {code:java} Exception in thread "main" java.io.IOException: Invalid entry trailer. not read the content? Occurred at byte: 146 at org.apache.commons.compress.archivers.ar.ArArchiveInputStream.getNextArEntry(ArArchiveInputStream.java:294) at org.example.Main.main(Main.java:31) {code} > ArArchiveInputStream.getNextArEntry() cause IOException "Invalid entry > trailer." > -------------------------------------------------------------------------------- > > Key: COMPRESS-678 > URL: https://issues.apache.org/jira/browse/COMPRESS-678 > Project: Commons Compress > Issue Type: Bug > Components: Archivers > Affects Versions: 1.26.1 > Reporter: takaaki nakama > Priority: Minor > > Using ArArchiveInputStream, reading content created by ArArchiveOutputStream > causes IOException "Invalid entry trailer." at specific conditions. > > h4. Conditions > 1. LongFILE_BSD mode is enabled > 2. Ar file contains at least two entries. > 1. First entry's name length is longer than 16bytes and odd > 2. First entry's body length is odd. > 3. Second entry's name length is odd > > h4. Cause > ArArchiveOutputStream add padding if entryOffset is odd. This entryOffset > only includes body length, but not entry name length. > [https://github.com/apache/commons-compress/blob/master/src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveOutputStream.java#L80] > > ArArchiveIutputStream try to remove padding when offset is odd. This offset > includes body length and name length. > [https://github.com/apache/commons-compress/blob/master/src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStream.java#L266] > > So encoding/decoding use different logics for padding, and at specific > conditions, ArArchiveIutputStream remove 1byte that is actually not padding > by mistake. > > > h4. Reproduction Code > > {code:java} > package test; > import java.io.File; > import java.io.FileInputStream; > import java.io.FileOutputStream; > import java.io.IOException; > import org.apache.commons.compress.archivers.ar.ArArchiveEntry; > import org.apache.commons.compress.archivers.ar.ArArchiveInputStream; > import org.apache.commons.compress.archivers.ar.ArArchiveOutputStream; > import org.junit.Test; > public class ArTest { > @Test > public void test() throws IOException { > File file = new File("test.ar"); > ArArchiveOutputStream arOut = new ArArchiveOutputStream(new > FileOutputStream(file)); > arOut.setLongFileMode(ArArchiveOutputStream.LONGFILE_BSD); > arOut.putArchiveEntry(new ArArchiveEntry("01234567891234567", 1)); > arOut.write(new byte[]{1}); > arOut.closeArchiveEntry(); > arOut.putArchiveEntry(new ArArchiveEntry("a", 1)); > arOut.write(new byte[]{1}); > arOut.closeArchiveEntry(); > arOut.close(); > ArArchiveInputStream arIn = new ArArchiveInputStream(new > FileInputStream(file)); > ArArchiveEntry entry = arIn.getNextArEntry(); > System.out.println(entry.getName()); > arIn.readAllBytes(); > entry = arIn.getNextArEntry(); // <- This line causes the exception. > System.out.println(entry.getName()); > } > }{code} > > > > h4. Error stack Trace > {code:java} > java.io.IOException: Invalid entry trailer. not read the content? Occurred at > byte: 146 > at > org.apache.commons.compress.archivers.ar.ArArchiveInputStream.getNextArEntry(ArArchiveInputStream.java:294) > at org.apache.druid.mila.ArTest.test(ArTest.java:34) > at > java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) > at java.base/java.lang.reflect.Method.invoke(Method.java:580) > at > org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59) > at > org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) > at > org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56) > at > org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) > at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) > at > org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100) > at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366) > at > org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103) > at > org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63) > at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331) > at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79) > at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329) > at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66) > at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293) > at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) > at org.junit.runners.ParentRunner.run(ParentRunner.java:413) > at > org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:112) > at > org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58) > at > org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:40) > at > org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:60) > at > org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:52) > at > java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) > at java.base/java.lang.reflect.Method.invoke(Method.java:580) > at > org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36) > at > org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) > at > org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33) > at > org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94) > at jdk.proxy1/jdk.proxy1.$Proxy2.processTestClass(Unknown Source) > at > org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:176) > at > org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129) > at > org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100) > at > org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60) > at > org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56) > at > org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113) > at > org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65) > at > worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) > at > worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) > {code} -- This message was sent by Atlassian Jira (v8.20.10#820010)