From 1a22123f5c7a236164cadc975673d2b3bcc4033f Mon Sep 17 00:00:00 2001 From: Stefan Bodewig Date: Mon, 3 Jun 2013 10:21:30 +0000 Subject: [PATCH] propely handle GNU longlink entries, PR 55040, submitted by Christoph Gysin git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@1488951 13f79535-47bb-0310-9956-ffa450edef68 --- CONTRIBUTORS | 1 + WHATSNEW | 3 + contributors.xml | 4 ++ .../org/apache/tools/tar/TarConstants.java | 5 ++ src/main/org/apache/tools/tar/TarEntry.java | 10 +++ .../org/apache/tools/tar/TarInputStream.java | 69 +++++++++++++------ 6 files changed, 71 insertions(+), 21 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 1e1efaea9..1dea64eef 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -50,6 +50,7 @@ Charles Hudak Charlie Hubbard Chris Povirk Christian Knorr +Christoph Gysin Christoph Wilhelms Christophe Labouisse Christopher A. Longo diff --git a/WHATSNEW b/WHATSNEW index 43b16c46a..0121f75f8 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -12,6 +12,9 @@ Fixed bugs: be able to read archives created by DotNetZip and maybe other archivers as well. + * TarInputStream should now properly read GNU longlink entries' names. + Bugzilla Report 55040. + Other changes: -------------- diff --git a/contributors.xml b/contributors.xml index a5754cc2b..4399cedb8 100644 --- a/contributors.xml +++ b/contributors.xml @@ -221,6 +221,10 @@ Christian Knorr + + Christoph + Gysin + Christoph Wilhelms diff --git a/src/main/org/apache/tools/tar/TarConstants.java b/src/main/org/apache/tools/tar/TarConstants.java index 7992bbbaa..2944a4055 100644 --- a/src/main/org/apache/tools/tar/TarConstants.java +++ b/src/main/org/apache/tools/tar/TarConstants.java @@ -237,6 +237,11 @@ public interface TarConstants { */ byte LF_CONTIG = (byte) '7'; + /** + * Identifies the *next* file on the tape as having a long linkname. + */ + byte LF_GNUTYPE_LONGLINK = (byte) 'K'; + /** * Identifies the *next* file on the tape as having a long name. */ diff --git a/src/main/org/apache/tools/tar/TarEntry.java b/src/main/org/apache/tools/tar/TarEntry.java index 03a699695..7cb22bbb2 100644 --- a/src/main/org/apache/tools/tar/TarEntry.java +++ b/src/main/org/apache/tools/tar/TarEntry.java @@ -652,6 +652,16 @@ public class TarEntry implements TarConstants { return linkFlag == LF_GNUTYPE_SPARSE; } + /** + * Indicate if this entry is a GNU long linkname block + * + * @return true if this is a long name extension provided by GNU tar + */ + public boolean isGNULongLinkEntry() { + return linkFlag == LF_GNUTYPE_LONGLINK + && name.equals(GNU_LONGLINK); + } + /** * Indicate if this entry is a GNU long name block * diff --git a/src/main/org/apache/tools/tar/TarInputStream.java b/src/main/org/apache/tools/tar/TarInputStream.java index 7baa397ff..62bbd625f 100644 --- a/src/main/org/apache/tools/tar/TarInputStream.java +++ b/src/main/org/apache/tools/tar/TarInputStream.java @@ -303,31 +303,25 @@ public class TarInputStream extends FilterInputStream { entryOffset = 0; entrySize = currEntry.getSize(); - if (currEntry.isGNULongNameEntry()) { - // read in the name - ByteArrayOutputStream longName = new ByteArrayOutputStream(); - int length = 0; - while ((length = read(SMALL_BUF)) >= 0) { - longName.write(SMALL_BUF, 0, length); - } - getNextEntry(); - if (currEntry == null) { + if (currEntry.isGNULongLinkEntry()) { + byte[] longLinkData = getLongNameData(); + if (longLinkData == null) { // Bugzilla: 40334 - // Malformed tar file - long entry name not followed by entry + // Malformed tar file - long link entry name not followed by + // entry return null; } - byte[] longNameData = longName.toByteArray(); - // remove trailing null terminator(s) - length = longNameData.length; - while (length > 0 && longNameData[length - 1] == 0) { - --length; - } - if (length != longNameData.length) { - byte[] l = new byte[length]; - System.arraycopy(longNameData, 0, l, 0, length); - longNameData = l; + currEntry.setLinkName(encoding.decode(longLinkData)); + } + + if (currEntry.isGNULongNameEntry()) { + byte[] longNameData = getLongNameData(); + if (longNameData == null) { + // Bugzilla: 40334 + // Malformed tar file - long entry name not followed by + // entry + return null; } - currEntry.setName(encoding.decode(longNameData)); } @@ -347,6 +341,39 @@ public class TarInputStream extends FilterInputStream { return currEntry; } + /** + * Get the next entry in this tar archive as longname data. + * + * @return The next entry in the archive as longname data, or null. + * @throws IOException on error + */ + protected byte[] getLongNameData() throws IOException { + // read in the name + ByteArrayOutputStream longName = new ByteArrayOutputStream(); + int length = 0; + while ((length = read(SMALL_BUF)) >= 0) { + longName.write(SMALL_BUF, 0, length); + } + getNextEntry(); + if (currEntry == null) { + // Bugzilla: 40334 + // Malformed tar file - long entry name not followed by entry + return null; + } + byte[] longNameData = longName.toByteArray(); + // remove trailing null terminator(s) + length = longNameData.length; + while (length > 0 && longNameData[length - 1] == 0) { + --length; + } + if (length != longNameData.length) { + byte[] l = new byte[length]; + System.arraycopy(longNameData, 0, l, 0, length); + longNameData = l; + } + return longNameData; + } + /** * Get the next record in this tar archive. This will skip * over any remaining data in the current entry, if there