This is an automated email from the ASF dual-hosted git repository. garydgregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-compress.git
commit 571208f7b594b95c9c7680ac6dfc5799b5232084 Author: Gary Gregory <[email protected]> AuthorDate: Mon Aug 10 18:39:44 2026 -0400 TarUtils now throws ArchiveException instead of IllegalArgumentException. --- src/changes/changes.xml | 1 + .../compress/archivers/tar/TarArchiveEntry.java | 4 ++-- .../commons/compress/archivers/tar/TarUtils.java | 28 ++++++++++++---------- .../apache/commons/compress/archivers/TarTest.java | 14 +++++------ .../compress/archivers/tar/TarUtilsTest.java | 26 ++++++++++---------- 5 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 328054d3a..34c494af4 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -106,6 +106,7 @@ The <action> type attribute can be add,update,fix,remove. <action type="fix" dev="ggregory" due-to="Gary Gregory">TAR ParsingUtils now throws the IOException subclass CompressException.</action> <action type="fix" dev="ggregory" due-to="Gary Gregory">TarArchiveOutputStream now throws ArchiveException instead of IllegalArgumentException.</action> <action type="fix" dev="ggregory" due-to="Gary Gregory">TarArchiveInputStream now throws ArchiveException instead of IllegalArgumentException.</action> + <action type="fix" dev="ggregory" due-to="Gary Gregory">TarUtils now throws ArchiveException instead of IllegalArgumentException.</action> <!-- FIX ar --> <action type="fix" dev="ggregory" due-to="Gary Gregory">ArArchiveInputStream.readGNUStringTable(byte[], int, int) now provides a better exception message, wrapping the underlying exception.</action> <action type="fix" dev="ggregory" due-to="Gary Gregory">ArArchiveInputStream.read(byte[], int, int) now throws ArchiveException instead of ArithmeticException.</action> diff --git a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java index 8a8114551..5d7442eb2 100644 --- a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java +++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java @@ -298,11 +298,11 @@ private static Instant parseInstantFromDecimalSeconds(final String value) throws } } - private static long parseOctalOrBinary(final byte[] header, final int offset, final int length, final boolean lenient) { + private static long parseOctalOrBinary(final byte[] header, final int offset, final int length, final boolean lenient) throws ArchiveException { if (lenient) { try { return TarUtils.parseOctalOrBinary(header, offset, length); - } catch (final IllegalArgumentException ex) { // NOSONAR + } catch (final ArchiveException ex) { // NOSONAR return UNKNOWN; } } diff --git a/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java b/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java index 6d329c00e..78132cc90 100644 --- a/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java +++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java @@ -420,7 +420,7 @@ static boolean isSpecialTarRecord(final TarArchiveEntry entry) { return entry.isGNULongLinkEntry() || entry.isGNULongNameEntry() || entry.isGlobalPaxHeader() || entry.isPaxHeader(); } - private static long parseBinaryBigInteger(final byte[] buffer, final int offset, final int length, final boolean negative) { + private static long parseBinaryBigInteger(final byte[] buffer, final int offset, final int length, final boolean negative) throws ArchiveException { final byte[] remainder = new byte[length - 1]; System.arraycopy(buffer, offset + 1, remainder, 0, length - 1); BigInteger val = new BigInteger(remainder); @@ -429,14 +429,14 @@ private static long parseBinaryBigInteger(final byte[] buffer, final int offset, val = val.add(NEG_1_BIG_INT).not(); } if (val.bitLength() > 63) { - throw new IllegalArgumentException("At offset " + offset + ", " + length + " byte binary number exceeds maximum signed long value"); + throw new ArchiveException("At offset " + offset + ", " + length + " byte binary number exceeds maximum signed long value"); } return negative ? -val.longValue() : val.longValue(); } - private static long parseBinaryLong(final byte[] buffer, final int offset, final int length, final boolean negative) { + private static long parseBinaryLong(final byte[] buffer, final int offset, final int length, final boolean negative) throws ArchiveException { if (length >= 9) { - throw new IllegalArgumentException("At offset " + offset + ", " + length + " byte binary number exceeds maximum signed long value"); + throw new ArchiveException("At offset " + offset + ", " + length + " byte binary number exceeds maximum signed long value"); } long val = 0; for (int i = 1; i < length; i++) { @@ -548,18 +548,18 @@ public static String parseName(final byte[] buffer, final int offset, final int * @param offset The offset into the buffer from which to parse. * @param length The maximum number of bytes to parse - must be at least 2 bytes. * @return The long value of the octal string. - * @throws IllegalArgumentException if the trailing space/NUL is missing or if an invalid byte is detected. + * @throws ArchiveException if the trailing space/NUL is missing or if an invalid byte is detected. */ - public static long parseOctal(final byte[] buffer, final int offset, final int length) { + public static long parseOctal(final byte[] buffer, final int offset, final int length) throws ArchiveException { return parseOctal(buffer, offset, length, "parseOctal()", false); } - static long parseOctal(final byte[] buffer, final int offset, final int length, final String context, final boolean lenient) { + static long parseOctal(final byte[] buffer, final int offset, final int length, final String context, final boolean lenient) throws ArchiveException { long result = 0; int end = offset + length; int start = offset; if (length < 2) { - throw new IllegalArgumentException(context + ": Length " + length + " must be at least 2"); + throw new ArchiveException(context + ": Length " + length + " must be at least 2"); } if (buffer[start] == 0) { return 0L; @@ -587,7 +587,7 @@ static long parseOctal(final byte[] buffer, final int offset, final int length, // When lenient, an early NUL ends the parsing (COMPRESS-707). return result; } - throw new IllegalArgumentException(context + ": " + exceptionMessage(buffer, offset, length, start, currentByte)); + throw new ArchiveException(context + ": " + exceptionMessage(buffer, offset, length, start, currentByte)); } result = (result << 3) + (currentByte - '0'); // convert from ASCII } @@ -602,11 +602,11 @@ static long parseOctal(final byte[] buffer, final int offset, final int length, * @param offset The offset into the buffer from which to parse. * @param length The maximum number of bytes to parse. * @return The long value of the octal or binary string. - * @throws IllegalArgumentException if the trailing space/NUL is missing or an invalid byte is detected in an octal number, or if a binary number would + * @throws ArchiveException if the trailing space/NUL is missing or an invalid byte is detected in an octal number, or if a binary number would * exceed the size of a signed long 64-bit integer. * @since 1.4 */ - public static long parseOctalOrBinary(final byte[] buffer, final int offset, final int length) { + public static long parseOctalOrBinary(final byte[] buffer, final int offset, final int length) throws ArchiveException { if ((buffer[offset] & 0x80) == 0) { return parseOctal(buffer, offset, length, "parseOctalOrBinary()", false); } @@ -886,11 +886,12 @@ static List<TarArchiveStructSparse> readSparseStructs(final byte[] buffer, final * * @param header tar header. * @return whether the checksum is reasonably good. + * @throws ArchiveException Thrown on invalid input. * @see <a href="https://en.wikipedia.org/wiki/Tar_(computing)#File_header">TAR header</a> * @see <a href="https://issues.apache.org/jira/browse/COMPRESS-191">COMPRESS-191</a> * @since 1.5 */ - public static boolean verifyCheckSum(final byte[] header) { + public static boolean verifyCheckSum(final byte[] header) throws ArchiveException { return verifyCheckSum(header, false); } @@ -909,11 +910,12 @@ public static boolean verifyCheckSum(final byte[] header) { * @param header tar header. * @param lenient Whether to allow out-of-spec formatting. * @return whether the checksum is reasonably good. + * @throws ArchiveException Thrown on invalid input. * @see <a href="https://en.wikipedia.org/wiki/Tar_(computing)#File_header">TAR header</a> * @see <a href="https://issues.apache.org/jira/browse/COMPRESS-191">COMPRESS-191</a> * @see <a href="https://issues.apache.org/jira/browse/COMPRESS-707">COMPRESS-707</a> */ - static boolean verifyCheckSum(final byte[] header, final boolean lenient) { + static boolean verifyCheckSum(final byte[] header, final boolean lenient) throws ArchiveException { final long storedSum = parseOctal(header, TarConstants.CHKSUM_OFFSET, TarConstants.CHKSUMLEN, "verifyCheckSum()", lenient); long unsignedSum = 0; long signedSum = 0; diff --git a/src/test/java/org/apache/commons/compress/archivers/TarTest.java b/src/test/java/org/apache/commons/compress/archivers/TarTest.java index f80b05f32..1d6861d87 100644 --- a/src/test/java/org/apache/commons/compress/archivers/TarTest.java +++ b/src/test/java/org/apache/commons/compress/archivers/TarTest.java @@ -19,10 +19,10 @@ package org.apache.commons.compress.archivers; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.Assert.assertNull; 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; @@ -86,9 +86,8 @@ 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"); + final ArchiveException e = assertThrows(ArchiveException.class, in::getNextEntry, "Expected IOException"); + assertNull(e.getCause()); } } @@ -303,13 +302,12 @@ void testTarFileCOMPRESS114() throws Exception { @Test void testTarFileCOMPRESS178() throws Exception { final File input = getFile("COMPRESS-178-fail.tar"); - final IOException e = assertThrows(ArchiveException.class, () -> { + final ArchiveException 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"); + }); + assertNull(e.getCause()); } @Test diff --git a/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java b/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java index 351d0586b..326e406a0 100644 --- a/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java +++ b/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java @@ -278,7 +278,7 @@ void testParseFromPAX01SparseHeadersRejectsOddNumberOfEntries() throws Exception } @Test - void testParseOctal() { + void testParseOctal() throws ArchiveException { long value; byte[] buffer; final long MAX_OCTAL = 077777777777L; // Allowed 11 digits @@ -305,7 +305,7 @@ void testParseOctal() { } @Test - void testParseOctalCompress330() { + void testParseOctalCompress330() throws ArchiveException { final long expected = 0100000; final byte[] buffer = { 32, 32, 32, 32, 32, 49, 48, 48, 48, 48, 48, 32 }; assertEquals(expected, TarUtils.parseOctalOrBinary(buffer, 0, buffer.length)); @@ -314,25 +314,25 @@ void testParseOctalCompress330() { @Test void testParseOctalEmbeddedSpace() { final byte[] buffer4 = " 0 07 ".getBytes(UTF_8); // Invalid - embedded space - assertThrows(IllegalArgumentException.class, () -> TarUtils.parseOctal(buffer4, 0, buffer4.length), + assertThrows(ArchiveException.class, () -> TarUtils.parseOctal(buffer4, 0, buffer4.length), "Expected IllegalArgumentException - embedded space"); } @Test void testParseOctalInvalid() { final byte[] buffer1 = ArrayUtils.EMPTY_BYTE_ARRAY; - assertThrows(IllegalArgumentException.class, () -> TarUtils.parseOctal(buffer1, 0, buffer1.length), - "Expected IllegalArgumentException - should be at least 2 bytes long"); + assertThrows(ArchiveException.class, () -> TarUtils.parseOctal(buffer1, 0, buffer1.length), + "Expected ArchiveException - should be at least 2 bytes long"); final byte[] buffer2 = { 0 }; // 1-byte array - assertThrows(IllegalArgumentException.class, () -> TarUtils.parseOctal(buffer2, 0, buffer2.length), - "Expected IllegalArgumentException - should be at least 2 bytes long"); + assertThrows(ArchiveException.class, () -> TarUtils.parseOctal(buffer2, 0, buffer2.length), + "Expected ArchiveException - should be at least 2 bytes long"); final byte[] buffer3 = "abcdef ".getBytes(UTF_8); // Invalid input - assertThrows(IllegalArgumentException.class, () -> TarUtils.parseOctal(buffer3, 0, buffer3.length), "Expected IllegalArgumentException"); + assertThrows(ArchiveException.class, () -> TarUtils.parseOctal(buffer3, 0, buffer3.length), "Expected IllegalArgumentException"); final byte[] buffer5 = " 0\00007 ".getBytes(UTF_8); // Invalid - embedded NUL - assertThrows(IllegalArgumentException.class, () -> TarUtils.parseOctal(buffer5, 0, buffer5.length), "Expected IllegalArgumentException - embedded NUL"); + assertThrows(ArchiveException.class, () -> TarUtils.parseOctal(buffer5, 0, buffer5.length), "Expected IllegalArgumentException - embedded NUL"); } @Test @@ -502,14 +502,14 @@ void testReadLongNameThrowsOnTruncation(final long size) throws IOException { } @Test - void testReadNegativeBinary12Byte() { + void testReadNegativeBinary12Byte() throws ArchiveException { final byte[] b = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xf1, (byte) 0xef, }; assertEquals(-3601L, TarUtils.parseOctalOrBinary(b, 0, 12)); } @Test - void testReadNegativeBinary8Byte() { + void testReadNegativeBinary8Byte() throws ArchiveException { final byte[] b = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xf1, (byte) 0xef, }; assertEquals(-3601L, TarUtils.parseOctalOrBinary(b, 0, 8)); } @@ -707,7 +707,7 @@ void testTrailers() throws ArchiveException { // https://issues.apache.org/jira/browse/COMPRESS-191 @Test - void testVerifyHeaderCheckSum() { + void testVerifyHeaderCheckSum() throws ArchiveException { final byte[] valid = { // from bla.tar 116, 101, 115, 116, 49, 46, 120, 109, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -759,7 +759,7 @@ void testVerifyHeaderCheckSum() { } @Test - void testWriteNegativeBinary8Byte() { + void testWriteNegativeBinary8Byte() throws ArchiveException { final byte[] b = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xf1, (byte) 0xef, }; assertEquals(-3601L, TarUtils.parseOctalOrBinary(b, 0, 8)); }
