This is an automated email from the ASF dual-hosted git repository. bodewig pushed a commit to branch catch-RuntimeExceptions in repository https://gitbox.apache.org/repos/asf/commons-compress.git
commit 6cb3167e9bdc92b96eed309f938fa1ec76c19444 Author: Stefan Bodewig <bode...@apache.org> AuthorDate: Sun Jun 6 07:36:08 2021 +0200 turn RuntimeExceptions into IOExceptions --- .../commons/compress/UnhandledInputException.java | 59 ++++++++++++++++++++++ .../compress/archivers/sevenz/SevenZFile.java | 19 ++++++- .../commons/compress/archivers/tar/TarFile.java | 13 +++++ .../commons/compress/archivers/zip/ZipFile.java | 14 ++++- 4 files changed, 102 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/apache/commons/compress/UnhandledInputException.java b/src/main/java/org/apache/commons/compress/UnhandledInputException.java new file mode 100644 index 0000000..920c538 --- /dev/null +++ b/src/main/java/org/apache/commons/compress/UnhandledInputException.java @@ -0,0 +1,59 @@ +/* + * 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 + * + * http://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; + +import java.io.IOException; + +/** + * Thrown if reading from an archive or compressed stream results in a RuntimeException. + * + * <p>Usually this means the input has been corrupt in a way Compress' + * code didn't detect by itself. If the input is not corrupt then + * you've found a bug in Compress and we ask you to report it.</p> + * + * @since 1.21 + */ +public class UnhandledInputException extends IOException { + + private static final long serialVersionUID = 1L; + + /** + * Wraps an unhandled RuntimeException for an input of unknown name. + */ + public UnhandledInputException(final RuntimeException ex) { + this(ex, null); + } + + /** + * Wraps an unhandled RuntimeException for an input with a known name. + * + * @param ex the unhandled excetion + * @param inputName name of the input + */ + public UnhandledInputException(final RuntimeException ex, final String inputName) { + super(buildMessage(inputName), ex); + } + + private static String buildMessage(final String name) { + return "Either the input" + + (name == null ? "" : " " + name) + + " is corrupt or you have found a bug in Apache Commons Compress. Please report it at" + + " https://issues.apache.org/jira/browse/COMPRESS if you think this is a bug."; + } +} diff --git a/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java b/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java index f4bec6c..351a858 100644 --- a/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java +++ b/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java @@ -45,6 +45,7 @@ import java.util.Map; import java.util.stream.Collectors; import java.util.zip.CRC32; +import org.apache.commons.compress.UnhandledInputException; import org.apache.commons.compress.utils.BoundedInputStream; import org.apache.commons.compress.utils.ByteUtils; import org.apache.commons.compress.utils.CRC32VerifyingInputStream; @@ -346,6 +347,8 @@ public class SevenZFile implements Closeable { this.password = null; } succeeded = true; + } catch (RuntimeException ex) { + throw new UnhandledInputException(ex, fileName); } finally { if (!succeeded && closeOnError) { this.channel.close(); @@ -410,7 +413,11 @@ public class SevenZFile implements Closeable { if (entry.getName() == null && options.getUseDefaultNameForUnnamedEntries()) { entry.setName(getDefaultName()); } - buildDecodingStream(currentEntryIndex, false); + try { + buildDecodingStream(currentEntryIndex, false); + } catch (RuntimeException ex) { + throw new UnhandledInputException(ex); + } uncompressedBytesReadFromCurrentEntry = compressedBytesReadFromCurrentEntry = 0; return entry; } @@ -510,7 +517,7 @@ public class SevenZFile implements Closeable { if (result.packSizes.length > 0 && result.files.length > 0) { return result; } - } catch (final Exception ignore) { + } catch (Exception ignore) { // Wrong guess... } } @@ -1899,11 +1906,15 @@ public class SevenZFile implements Closeable { * if an I/O error has occurred */ public int read() throws IOException { + try { final int b = getCurrentStream().read(); if (b >= 0) { uncompressedBytesReadFromCurrentEntry++; } return b; + } catch (RuntimeException ex) { + throw new UnhandledInputException(ex, fileName); + } } private InputStream getCurrentStream() throws IOException { @@ -1981,6 +1992,7 @@ public class SevenZFile implements Closeable { * if an I/O error has occurred */ public int read(final byte[] b, final int off, final int len) throws IOException { + try { if (len == 0) { return 0; } @@ -1989,6 +2001,9 @@ public class SevenZFile implements Closeable { uncompressedBytesReadFromCurrentEntry += cnt; } return cnt; + } catch (RuntimeException ex) { + throw new UnhandledInputException(ex, fileName); + } } /** diff --git a/src/main/java/org/apache/commons/compress/archivers/tar/TarFile.java b/src/main/java/org/apache/commons/compress/archivers/tar/TarFile.java index e79d390..d1822e1 100644 --- a/src/main/java/org/apache/commons/compress/archivers/tar/TarFile.java +++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarFile.java @@ -32,6 +32,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import org.apache.commons.compress.UnhandledInputException; import org.apache.commons.compress.archivers.zip.ZipEncoding; import org.apache.commons.compress.archivers.zip.ZipEncodingHelper; import org.apache.commons.compress.utils.ArchiveUtils; @@ -239,6 +240,14 @@ public class TarFile implements Closeable { return null; } + try { + return getNextTarEntryInternal(); + } catch (RuntimeException ex) { + throw new UnhandledInputException(ex); + } + } + + private TarArchiveEntry getNextTarEntryInternal() throws IOException { if (currEntry != null) { // Skip to the end of the entry repositionForwardTo(currEntry.getDataOffset() + currEntry.getSize()); @@ -678,11 +687,15 @@ public class TarFile implements Closeable { } final int totalRead; + try { if (entry.isSparse()) { totalRead = readSparse(entryOffset, buf, buf.limit()); } else { totalRead = readArchive(pos, buf); } + } catch (RuntimeException ex) { + throw new UnhandledInputException(ex); + } if (totalRead == -1) { if (buf.array().length > 0) { diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java index 8792563..cd1b01a 100644 --- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java +++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java @@ -42,6 +42,7 @@ import java.util.Map; import java.util.zip.Inflater; import java.util.zip.ZipException; +import org.apache.commons.compress.UnhandledInputException; import org.apache.commons.compress.archivers.EntryStreamOffsets; import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; import org.apache.commons.compress.compressors.deflate64.Deflate64CompressorInputStream; @@ -376,6 +377,8 @@ public class ZipFile implements Closeable { } fillNameMap(); success = true; + } catch (RuntimeException ex) { + throw new UnhandledInputException(ex, archiveName); } catch (final IOException e) { throw new IOException("Error on ZipFile " + archiveName, e); } finally { @@ -564,7 +567,16 @@ public class ZipFile implements Closeable { if (!(ze instanceof Entry)) { return null; } - // cast validity is checked just above + try { + // cast validity is checked just above + return getInputStreamInternal((Entry) ze); + } catch (RuntimeException ex) { + throw new UnhandledInputException(ex); + } + } + + private InputStream getInputStreamInternal(final Entry ze) + throws IOException { ZipUtil.checkRequestedFeatures(ze); final long start = getDataOffset(ze);