You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by bo...@apache.org on 2012/07/07 07:19:39 UTC
svn commit: r1358504 - in /commons/proper/compress/trunk/src:
main/java/org/apache/commons/compress/archivers/tar/
test/java/org/apache/commons/compress/archivers/tar/
Author: bodewig
Date: Sat Jul 7 05:19:39 2012
New Revision: 1358504
URL: http://svn.apache.org/viewvc?rev=1358504&view=rev
Log:
COMPRESS-191 add checksum check to TarArchiveEntry. Submitted by Jukka Zitting.
Modified:
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java
commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveEntryTest.java
commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java
commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java
Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java?rev=1358504&r1=1358503&r2=1358504&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java (original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java Sat Jul 7 05:19:39 2012
@@ -132,6 +132,9 @@ public class TarArchiveEntry implements
/** The entry's modification time. */
private long modTime;
+ /** If the header checksum is reasonably correct. */
+ private boolean checkSumOK;
+
/** The entry's link flag. */
private byte linkFlag;
@@ -551,6 +554,17 @@ public class TarArchiveEntry implements
}
/**
+ * Get this entry's checksum status.
+ *
+ * @return if the header checksum is reasonably correct
+ * @see TarUtils#verifyCheckSum(byte[])
+ * @since 1.5
+ */
+ public boolean isCheckSumOK() {
+ return checkSumOK;
+ }
+
+ /**
* Get this entry's file.
*
* @return This entry's file.
@@ -942,6 +956,7 @@ public class TarArchiveEntry implements
offset += SIZELEN;
modTime = TarUtils.parseOctalOrBinary(header, offset, MODTIMELEN);
offset += MODTIMELEN;
+ checkSumOK = TarUtils.verifyCheckSum(header);
offset += CHKSUMLEN;
linkFlag = header[offset++];
linkName = oldStyle ? TarUtils.parseName(header, offset, NAMELEN)
Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java?rev=1358504&r1=1358503&r2=1358504&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java (original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java Sat Jul 7 05:19:39 2012
@@ -69,6 +69,11 @@ public interface TarConstants {
int CHKSUMLEN = 8;
/**
+ * Offset of the checksum field within header record.
+ */
+ int CHKSUM_OFFSET = 148;
+
+ /**
* The length of the size field in a header buffer.
* Includes the trailing space or NUL.
*/
Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java?rev=1358504&r1=1358503&r2=1358504&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java (original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java Sat Jul 7 05:19:39 2012
@@ -18,6 +18,9 @@
*/
package org.apache.commons.compress.archivers.tar;
+import static org.apache.commons.compress.archivers.tar.TarConstants.CHKSUMLEN;
+import static org.apache.commons.compress.archivers.tar.TarConstants.CHKSUM_OFFSET;
+
import java.io.IOException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
@@ -558,4 +561,63 @@ public class TarUtils {
return sum;
}
+ /**
+ * Wikipedia <a href="http://en.wikipedia.org/wiki/Tar_(file_format)#File_header">says</a>:
+ * <blockquote>
+ * The checksum is calculated by taking the sum of the unsigned byte values
+ * of the header block with the eight checksum bytes taken to be ascii
+ * spaces (decimal value 32). It is stored as a six digit octal number with
+ * leading zeroes followed by a NUL and then a space. Various
+ * implementations do not adhere to this format. For better compatibility,
+ * ignore leading and trailing whitespace, and get the first six digits. In
+ * addition, some historic tar implementations treated bytes as signed.
+ * Implementations typically calculate the checksum both ways, and treat it
+ * as good if either the signed or unsigned sum matches the included
+ * checksum.
+ * </blockquote>
+ * <p>
+ * In addition there are
+ * <a href="https://issues.apache.org/jira/browse/COMPRESS-117">some tar files</a>
+ * that seem to have parts of their header cleared to zero (no detectable
+ * magic bytes, etc.) but still have a reasonable-looking checksum field
+ * present. It looks like we can detect such cases reasonably well by
+ * checking whether the stored checksum is <em>greater than</em> the
+ * computed unsigned checksum. That check is unlikely to pass on some
+ * random file header, as it would need to have a valid sequence of
+ * octal digits in just the right place.
+ * <p>
+ * The return value of this method should be treated as a best-effort
+ * heuristic rather than an absolute and final truth. The checksum
+ * verification logic may well evolve over time as more special cases
+ * are encountered.
+ *
+ * @param header tar header
+ * @return whether the checksum is reasonably good
+ * @see <a href="https://issues.apache.org/jira/browse/COMPRESS-191">COMPRESS-191</a>
+ * @since 1.5
+ */
+ public static boolean verifyCheckSum(byte[] header) {
+ long storedSum = 0;
+ long unsignedSum = 0;
+ long signedSum = 0;
+
+ int digits = 0;
+ for (int i = 0; i < header.length; i++) {
+ byte b = header[i];
+ if (CHKSUM_OFFSET <= i && i < CHKSUM_OFFSET + CHKSUMLEN) {
+ if ('0' <= b && b <= '7' && digits++ < 6) {
+ storedSum = storedSum * 8 + b - '0';
+ } else if (digits > 0) {
+ digits = 6; // only look at the first octal digit sequence
+ }
+ b = ' ';
+ }
+ unsignedSum += 0xff & b;
+ signedSum += b;
+ }
+
+ return storedSum == unsignedSum || storedSum == signedSum
+ || storedSum > unsignedSum; // COMPRESS-177
+ }
+
}
Modified: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveEntryTest.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveEntryTest.java?rev=1358504&r1=1358503&r2=1358504&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveEntryTest.java (original)
+++ commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveEntryTest.java Sat Jul 7 05:19:39 2012
@@ -80,15 +80,19 @@ public class TarArchiveEntryTest extends
t = tin.getNextTarEntry();
assertNotNull(t);
assertEquals("/", t.getName());
+ assertTrue(t.isCheckSumOK());
t = tin.getNextTarEntry();
assertNotNull(t);
assertEquals("foo.txt", t.getName());
+ assertTrue(t.isCheckSumOK());
t = tin.getNextTarEntry();
assertNotNull(t);
assertEquals("bar.txt", t.getName());
+ assertTrue(t.isCheckSumOK());
t = tin.getNextTarEntry();
assertNotNull(t);
assertEquals("baz.txt", t.getName());
+ assertTrue(t.isCheckSumOK());
} finally {
if (tin != null) {
tin.close();
Modified: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java?rev=1358504&r1=1358503&r2=1358504&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java (original)
+++ commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java Sat Jul 7 05:19:39 2012
@@ -76,6 +76,7 @@ public class TarArchiveInputStreamTest {
assertEquals("sample/link-to-txt-file.lnk", tae.getName());
assertEquals(new Date(0), tae.getLastModifiedDate());
assertTrue(tae.isSymbolicLink());
+ assertTrue(tae.isCheckSumOK());
} finally {
if (in != null) {
in.close();
@@ -105,6 +106,7 @@ public class TarArchiveInputStreamTest {
cal.set(1969, 11, 31, 23, 59, 59);
cal.set(Calendar.MILLISECOND, 0);
assertEquals(cal.getTime(), tae.getLastModifiedDate());
+ assertTrue(tae.isCheckSumOK());
} finally {
if (in != null) {
in.close();
Modified: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java?rev=1358504&r1=1358503&r2=1358504&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java (original)
+++ commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java Sat Jul 7 05:19:39 2012
@@ -239,4 +239,97 @@ public class TarUtilsTest extends TestCa
assertEquals(-3601l, TarUtils.parseOctalOrBinary(b, 0, 8));
}
+ // https://issues.apache.org/jira/browse/COMPRESS-191
+ public void testVerifyHeaderCheckSum() {
+ 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, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 48, 48, 48, 48, 54, 52, 52, 0, 48, 48, 48, 48, 55, 54, 53,
+ 0, 48, 48, 48, 48, 55, 54, 53, 0, 48, 48, 48, 48, 48, 48, 48,
+ 49, 49, 52, 50, 0, 49, 48, 55, 49, 54, 53, 52, 53, 54, 50, 54,
+ 0, 48, 49, 50, 50, 54, 48, 0, 32, 48, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 117, 115, 116, 97, 114, 32, 32, 0,
+ 116, 99, 117, 114, 100, 116, 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, 116, 99, 117,
+ 114, 100, 116, 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, 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, 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 };
+ assertTrue(TarUtils.verifyCheckSum(valid));
+
+ byte[] compress117 = { // from COMPRESS-117
+ 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, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 48, 48, 48, 48, 54, 52, 52, 0, 48, 48, 48, 48, 55, 54, 53,
+ 0, 48, 48, 48, 48, 55, 54, 53, 0, 48, 48, 48, 48, 48, 48, 48,
+ 49, 49, 52, 50, 0, 49, 48, 55, 49, 54, 53, 52, 53, 54, 50, 54,
+ 0, 48, 49, 50, 50, 54, 48, 0, 32, 48, 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, 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, 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, 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, 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 };
+ assertTrue(TarUtils.verifyCheckSum(compress117));
+
+ byte[] invalid = { // from the testAIFF.aif file in Tika
+ 70, 79, 82, 77, 0, 0, 15, 46, 65, 73, 70, 70, 67, 79, 77, 77,
+ 0, 0, 0, 18, 0, 2, 0, 0, 3, -64, 0, 16, 64, 14, -84, 68, 0, 0,
+ 0, 0, 0, 0, 83, 83, 78, 68, 0, 0, 15, 8, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, -1, -1, 0, 1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1,
+ 0, 0, 0, 0, 0, 0, -1, -1, 0, 2, -1, -2, 0, 2, -1, -1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, -1, -1, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, -1, -1, 0, 1, -1, -2, 0, 1, -1, -1, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0,
+ 2, -1, -2, 0, 2, -1, -1, 0, 0, 0, 1, -1, -1, 0, 1, -1, -1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -2, 0, 2, -1, -2, 0, 1, 0, 0,
+ 0, 1, -1, -1, 0, 0, 0, 1, -1, -1, 0, 0, 0, 1, -1, -2, 0, 2,
+ -1, -1, 0, 0, 0, 0, 0, 0, -1, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 1, -1, -1, 0, 2, -1, -2,
+ 0, 2, -1, -2, 0, 2, -1, -2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, -1,
+ -2, 0, 2, -1, -2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ -1, -1, 0, 1, 0, 0, -1, -1, 0, 2, -1, -2, 0, 2, -1, -1, 0, 0,
+ 0, 0, 0, 0, -1, -1, 0, 1, -1, -1, 0, 1, -1, -1, 0, 2, -1, -2,
+ 0, 1, 0, 0, -1, -1, 0, 2, -1, -2, 0, 2, -1, -2, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0,
+ 0, -1, -1, 0, 1, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -2, 0, 2, -1, -1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -2, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0, 0, -1, -1, 0, 2, -1, -2,
+ 0, 2, -1, -2, 0, 2, -1, -1, 0, 0, 0, 0, -1, -1, 0, 1, -1, -1,
+ 0, 1, -1, -1, 0, 1, -1, -1, 0, 1, -1, -1, 0, 1, 0, 0, 0, 0,
+ -1, -1, 0, 2, -1, -2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, -1, -1, 0, 0, 0, 0, -1, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1 };
+ assertFalse(TarUtils.verifyCheckSum(invalid));
+ }
+
}