This is an automated email from the ASF dual-hosted git repository.
peterlee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-compress.git
The following commit(s) were added to refs/heads/master by this push:
new b927280 COMPRESS-544 : truncated tar detect
b927280 is described below
commit b92728060ae6b82904d7d1453b05223f2917fc73
Author: PeterAlfredLee <[email protected]>
AuthorDate: Thu Aug 13 16:30:55 2020 +0800
COMPRESS-544 : truncated tar detect
TarArchiveInputStream can not detect truncated tar archive when skipping
bytes. This is a fix for it.
---
src/changes/changes.xml | 4 ++
.../archivers/tar/TarArchiveInputStream.java | 50 ++++++++++++++++++---
.../archivers/tar/TarArchiveInputStreamTest.java | 18 ++++++++
.../COMPRESS-544_truncated_in_content.tar | Bin 0 -> 2067 bytes
.../COMPRESS-544_truncated_in_padding.tar | Bin 0 -> 2076 bytes
5 files changed, 65 insertions(+), 7 deletions(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 934573d..4301093 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -173,6 +173,10 @@ The <action> type attribute can be add,update,fix,remove.
Fix for test fails on Windows. The tests are failing because the
default charset is not UTF-8.
</action>
+ <action issue="COMPRESS-544" type="fix" date="2020-08-13" due-to="Aditya
Prasad" dev="PeterLee">
+ TarArchiveInputStream can not detect a truncated tar in skip()
+ and skipRecordPadding().
+ </action>
</release>
<release version="1.20" date="2020-02-08"
description="Release 1.20">
diff --git
a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
index 5c08ba0..3b99366 100644
---
a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
+++
b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
@@ -24,6 +24,7 @@
package org.apache.commons.compress.archivers.tar;
import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
@@ -261,8 +262,8 @@ public class TarArchiveInputStream extends
ArchiveInputStream {
* @param n
* the number of bytes to be skipped.
* @return the actual number of bytes skipped.
- * @throws IOException
- * if some other I/O error occurs.
+ * @throws IOException if a truncated tar archive is detected
+ * or some other I/O error occurs
*/
@Override
public long skip(final long n) throws IOException {
@@ -270,13 +271,19 @@ public class TarArchiveInputStream extends
ArchiveInputStream {
return 0;
}
+ final long availableOfInputStream = inputStream.available();
final long available = currEntry.getRealSize() - entryOffset;
- final long skipped;
+ final long numToSkip = Math.min(n, available);
+ long skipped;
+
if (!currEntry.isSparse()) {
- skipped = IOUtils.skip(inputStream, Math.min(n, available));
+ skipped = IOUtils.skip(inputStream, numToSkip);
} else {
- skipped = skipSparse(Math.min(n, available));
+ skipped = skipSparse(numToSkip);
}
+
+ skipped = getActuallySkipped(availableOfInputStream, skipped,
numToSkip);
+
count(skipped);
entryOffset += skipped;
return skipped;
@@ -436,18 +443,47 @@ public class TarArchiveInputStream extends
ArchiveInputStream {
/**
* The last record block should be written at the full size, so skip any
- * additional space used to fill a record after an entry
+ * additional space used to fill a record after an entry.
+ *
+ * @throws IOException if a truncated tar archive is detected
*/
private void skipRecordPadding() throws IOException {
if (!isDirectory() && this.entrySize > 0 && this.entrySize %
this.recordSize != 0) {
+ final long available = inputStream.available();
final long numRecords = (this.entrySize / this.recordSize) + 1;
final long padding = (numRecords * this.recordSize) -
this.entrySize;
- final long skipped = IOUtils.skip(inputStream, padding);
+ long skipped = IOUtils.skip(inputStream, padding);
+
+ skipped = getActuallySkipped(available, skipped, padding);
+
count(skipped);
}
}
/**
+ * For FileInputStream, the skip always return the number you input, so we
+ * need the available bytes to determine how many bytes are actually
skipped
+ *
+ * @param available available bytes returned by inputStream.available()
+ * @param skipped skipped bytes returned by inputStream.skip()
+ * @param expected bytes expected to skip
+ * @return number of bytes actually skipped
+ * @throws IOException if a truncated tar archive is detected
+ */
+ private long getActuallySkipped(final long available, final long skipped,
final long expected) throws IOException {
+ long actuallySkipped = skipped;
+ if (inputStream instanceof FileInputStream) {
+ actuallySkipped = Math.min(skipped, available);
+ }
+
+ if (actuallySkipped != expected) {
+ throw new IOException("Truncated TAR archive");
+ }
+
+ return actuallySkipped;
+ }
+
+ /**
* Get the next entry in this tar archive as longname data.
*
* @return The next entry in the archive as longname data, or null.
diff --git
a/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java
b/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java
index 8218af5..924542f 100644
---
a/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java
+++
b/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java
@@ -442,6 +442,24 @@ public class TarArchiveInputStreamTest extends
AbstractTestCase {
}
}
+ @Test(expected = IOException.class)
+ public void testParseTarTruncatedInPadding() throws IOException {
+ try (FileInputStream in = new
FileInputStream(getFile("./COMPRESS-544_truncated_in_padding.tar"));
+ TarArchiveInputStream archive = new TarArchiveInputStream(in)) {
+ while (archive.getNextTarEntry() != null) {
+ }
+ }
+ }
+
+ @Test(expected = IOException.class)
+ public void testParseTarTruncatedInContent() throws IOException {
+ try (FileInputStream in = new
FileInputStream(getFile("./COMPRESS-544_truncated_in_content.tar"));
+ TarArchiveInputStream archive = new TarArchiveInputStream(in)) {
+ while (archive.getNextTarEntry() != null) {
+ }
+ }
+ }
+
private TarArchiveInputStream getTestStream(final String name) {
return new TarArchiveInputStream(
TarArchiveInputStreamTest.class.getResourceAsStream(name));
diff --git a/src/test/resources/COMPRESS-544_truncated_in_content.tar
b/src/test/resources/COMPRESS-544_truncated_in_content.tar
new file mode 100644
index 0000000..bfcfb9b
Binary files /dev/null and
b/src/test/resources/COMPRESS-544_truncated_in_content.tar differ
diff --git a/src/test/resources/COMPRESS-544_truncated_in_padding.tar
b/src/test/resources/COMPRESS-544_truncated_in_padding.tar
new file mode 100644
index 0000000..94caf3f
Binary files /dev/null and
b/src/test/resources/COMPRESS-544_truncated_in_padding.tar differ