From 18e098d81f228e4e36bbbbf98ed41203556a422c Mon Sep 17 00:00:00 2001
From: Stefan Bodewig
Date: Fri, 9 Aug 2013 07:00:25 +0000
Subject: [PATCH] merge TAR long link handling fix by Emmanuel Bourg
git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@1512171 13f79535-47bb-0310-9956-ffa450edef68
---
WHATSNEW | 2 +
.../org/apache/tools/tar/TarOutputStream.java | 86 +++++++++++++------
2 files changed, 61 insertions(+), 27 deletions(-)
diff --git a/WHATSNEW b/WHATSNEW
index 36fdf95bb..9b30e00d0 100644
--- a/WHATSNEW
+++ b/WHATSNEW
@@ -14,6 +14,8 @@ Other changes:
* Documentation fix for if/unless attributes. PR 55359.
+ * tar entries with long link names are now handled the same way as
+ entries with long names.
Changes from Ant 1.9.1 TO Ant 1.9.2
===================================
diff --git a/src/main/org/apache/tools/tar/TarOutputStream.java b/src/main/org/apache/tools/tar/TarOutputStream.java
index af8ada6bd..9eddaa02b 100644
--- a/src/main/org/apache/tools/tar/TarOutputStream.java
+++ b/src/main/org/apache/tools/tar/TarOutputStream.java
@@ -273,31 +273,13 @@ public class TarOutputStream extends FilterOutputStream {
}
Map paxHeaders = new HashMap();
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
- TarEntry longLinkEntry = new TarEntry(TarConstants.GNU_LONGLINK,
- TarConstants.LF_GNUTYPE_LONGNAME);
-
- longLinkEntry.setSize(nameLen + 1); // +1 for NUL
- putNextEntry(longLinkEntry);
- write(encodedName.array(), encodedName.arrayOffset(), nameLen);
- write(0); // NUL terminator
- closeEntry();
- } 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);
@@ -310,10 +292,10 @@ public class TarOutputStream extends FilterOutputStream {
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) {
@@ -596,4 +578,54 @@ public class TarOutputStream extends FilterOutputStream {
+ maxValue + " )");
}
}
+
+ /**
+ * Handles long file or link names according to the longFileMode setting.
+ *
+ * I.e. if the given name is too long to be written to a plain
+ * tar header then
+ *
+ * - it creates a pax header who's name is given by the
+ * paxHeaderName parameter if longFileMode is POSIX
+ * - it creates a GNU longlink entry who's type is given by
+ * the linkType parameter if longFileMode is GNU
+ * - throws an exception othewise.
+ *
+ *
+ * @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 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
+ TarEntry longLinkEntry =
+ new TarEntry(TarConstants.GNU_LONGLINK, linkType);
+
+ longLinkEntry.setSize(len + 1); // +1 for NUL
+ putNextEntry(longLinkEntry);
+ write(encodedName.array(), encodedName.arrayOffset(), len);
+ write(0); // NUL terminator
+ closeEntry();
+ } else if (longFileMode != LONGFILE_TRUNCATE) {
+ throw new RuntimeException(paxHeaderName + " '" + name
+ + "' is too long ( > "
+ + TarConstants.NAMELEN + " bytes)");
+ }
+ }
+ return false;
+ }
}