@@ -273,31 +273,13 @@ public class TarOutputStream extends FilterOutputStream {
}
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
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.
*
* <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
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;
}
}