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; + } }