Author: bodewig
Date: Fri Aug 9 06:51:18 2013
New Revision: 1512161
URL: http://svn.apache.org/r1512161
Log:
COMPRESS-237 properly write TAR entries with long link names. Patch by
Emmanuel Bourg
Modified:
commons/proper/compress/trunk/src/changes/changes.xml
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java
Modified: commons/proper/compress/trunk/src/changes/changes.xml
URL:
http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/changes/changes.xml?rev=1512161&r1=1512160&r2=1512161&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/changes/changes.xml (original)
+++ commons/proper/compress/trunk/src/changes/changes.xml Fri Aug 9 06:51:18
2013
@@ -90,6 +90,11 @@ The <action> type attribute can be add,u
CpioArchiveInputStream failed to read archives created by
Redline RPM.
</action>
+ <action type="fix" date="2013-08-09" issue="COMPRESS-237"
+ due-to="Emmanuel Bourg">
+ TarArchiveOutputStream now properly handles link names that
+ are too long to fit into a traditional TAR header.
+ </action>
</release>
<release version="1.5" date="2013-03-14"
description="Release 1.5">
Modified:
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java
URL:
http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java?rev=1512161&r1=1512160&r2=1512161&view=diff
==============================================================================
---
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java
(original)
+++
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java
Fri Aug 9 06:51:18 2013
@@ -271,31 +271,13 @@ public class TarArchiveOutputStream exte
TarArchiveEntry entry = (TarArchiveEntry) archiveEntry;
Map<String, String> paxHeaders = new HashMap<String, String>();
final String entryName = entry.getName();
- final ByteBuffer encodedName = encoding.encode(entryName);
- final int nameLen = encodedName.limit() - encodedName.position();
- boolean paxHeaderContainsPath = false;
- if (nameLen >= TarConstants.NAMELEN) {
+ boolean paxHeaderContainsPath = handleLongName(entryName, paxHeaders,
"path",
+
TarConstants.LF_GNUTYPE_LONGNAME);
- if (longFileMode == LONGFILE_POSIX) {
- paxHeaders.put("path", entryName);
- paxHeaderContainsPath = true;
- } else if (longFileMode == LONGFILE_GNU) {
- // create a TarEntry for the LongLink, the contents
- // of which are the entry's name
- TarArchiveEntry longLinkEntry = new
TarArchiveEntry(TarConstants.GNU_LONGLINK,
-
TarConstants.LF_GNUTYPE_LONGNAME);
-
- longLinkEntry.setSize(nameLen + 1); // +1 for NUL
- putArchiveEntry(longLinkEntry);
- write(encodedName.array(), encodedName.arrayOffset(), nameLen);
- write(0); // NUL terminator
- closeArchiveEntry();
- } else if (longFileMode != LONGFILE_TRUNCATE) {
- throw new RuntimeException("file name '" + entryName
- + "' is too long ( > "
- + TarConstants.NAMELEN + " bytes)");
- }
- }
+ final String linkName = entry.getLinkName();
+ boolean paxHeaderContainsLinkPath = linkName != null
+ && handleLongName(linkName, paxHeaders, "linkpath",
+ TarConstants.LF_GNUTYPE_LONGLINK);
if (bigNumberMode == BIGNUMBER_POSIX) {
addPaxHeadersForBigNumbers(paxHeaders, entry);
@@ -308,10 +290,10 @@ public class TarArchiveOutputStream exte
paxHeaders.put("path", entryName);
}
- if (addPaxHeadersForNonAsciiNames
+ if (addPaxHeadersForNonAsciiNames && !paxHeaderContainsLinkPath
&& (entry.isLink() || entry.isSymbolicLink())
- && !ASCII.canEncode(entry.getLinkName())) {
- paxHeaders.put("linkpath", entry.getLinkName());
+ && !ASCII.canEncode(linkName)) {
+ paxHeaders.put("linkpath", linkName);
}
if (paxHeaders.size() > 0) {
@@ -630,4 +612,54 @@ public class TarArchiveOutputStream exte
+ maxValue + " )");
}
}
+
+ /**
+ * Handles long file or link names according to the longFileMode setting.
+ *
+ * <p>I.e. if the given name is too long to be written to a plain
+ * tar header then
+ * <ul>
+ * <li>it creates a pax header who's name is given by the
+ * paxHeaderName parameter if longFileMode is POSIX</li>
+ * <li>it creates a GNU longlink entry who's type is given by
+ * the linkType parameter if longFileMode is GNU</li>
+ * <li>throws an exception othewise.</li>
+ * </ul></p>
+ *
+ * @param name the name to write
+ * @param paxHeaders current map of pax headers
+ * @param paxHeaderName name of the pax header to write
+ * @param linkType type of the GNU entry to write
+ * @return whether a pax header has been written.
+ */
+ private boolean handleLongName(String name,
+ Map<String, String> paxHeaders,
+ String paxHeaderName, byte linkType)
+ throws IOException {
+ final ByteBuffer encodedName = encoding.encode(name);
+ final int len = encodedName.limit() - encodedName.position();
+ if (len >= TarConstants.NAMELEN) {
+
+ if (longFileMode == LONGFILE_POSIX) {
+ paxHeaders.put(paxHeaderName, name);
+ return true;
+ } else if (longFileMode == LONGFILE_GNU) {
+ // create a TarEntry for the LongLink, the contents
+ // of which are the link's name
+ TarArchiveEntry longLinkEntry =
+ new TarArchiveEntry(TarConstants.GNU_LONGLINK, linkType);
+
+ longLinkEntry.setSize(len + 1); // +1 for NUL
+ putArchiveEntry(longLinkEntry);
+ write(encodedName.array(), encodedName.arrayOffset(), len);
+ write(0); // NUL terminator
+ closeArchiveEntry();
+ } else if (longFileMode != LONGFILE_TRUNCATE) {
+ throw new RuntimeException(paxHeaderName + " '" + name
+ + "' is too long ( > "
+ + TarConstants.NAMELEN + " bytes)");
+ }
+ }
+ return false;
+ }
}