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