diff --git a/core/pom.xml b/core/pom.xml index 53cc2a51d8..f2ab73fd6c 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -276,11 +276,6 @@ THE SOFTWARE. commons-beanutils 1.8.3 - - org.apache.commons - commons-compress - 1.9 - javax.mail mail diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index 7a75f27d05..d2778ba37e 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -33,6 +33,7 @@ import hudson.model.AbstractProject; import hudson.model.Computer; import hudson.model.Item; import hudson.model.TaskListener; +import hudson.org.apache.tools.tar.TarInputStream; import hudson.os.PosixAPI; import hudson.os.PosixException; import hudson.remoting.Callable; @@ -69,6 +70,7 @@ import org.apache.commons.io.input.CountingInputStream; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.types.FileSet; +import org.apache.tools.tar.TarEntry; import org.apache.tools.zip.ZipEntry; import org.apache.tools.zip.ZipFile; import org.kohsuke.stapler.Stapler; @@ -118,8 +120,6 @@ import static hudson.Util.*; import javax.annotation.Nonnull; import javax.annotation.Nullable; import jenkins.security.MasterToSlaveCallable; -import org.apache.commons.compress.archivers.tar.TarArchiveEntry; -import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.jenkinsci.remoting.RoleChecker; import org.jenkinsci.remoting.RoleSensitive; @@ -2268,15 +2268,12 @@ public final class FilePath implements Serializable { /** * Reads from a tar stream and stores obtained files to the base dir. - * @since TODO supports large files > 10 GB, migration to commons-compress */ private void readFromTar(String name, File baseDir, InputStream in) throws IOException { - TarArchiveInputStream t = new TarArchiveInputStream(in); - - // TarInputStream t = new TarInputStream(in); + TarInputStream t = new TarInputStream(in); try { - TarArchiveEntry te; - while ((te = t.getNextTarEntry()) != null) { + TarEntry te; + while ((te = t.getNextEntry()) != null) { File f = new File(baseDir,te.getName()); if(te.isDirectory()) { mkdirs(f); @@ -2285,7 +2282,8 @@ public final class FilePath implements Serializable { if (parent != null) mkdirs(parent); writing(f); - if (te.isSymbolicLink()) { + byte linkFlag = (Byte) LINKFLAG_FIELD.get(te); + if (linkFlag==TarEntry.LF_SYMLINK) { new FilePath(f).symlinkTo(te.getLinkName(), TaskListener.NULL); } else { IOUtils.copy(t,f); @@ -2302,6 +2300,8 @@ public final class FilePath implements Serializable { } catch (InterruptedException e) { Thread.currentThread().interrupt(); // process this later throw new IOException("Failed to extract "+name,e); + } catch (IllegalAccessException e) { + throw new IOException("Failed to extract "+name,e); } finally { t.close(); } @@ -2725,6 +2725,20 @@ public final class FilePath implements Serializable { } }; + private static final Field LINKFLAG_FIELD = getTarEntryLinkFlagField(); + + private static Field getTarEntryLinkFlagField() { + try { + Field f = TarEntry.class.getDeclaredField("linkFlag"); + f.setAccessible(true); + return f; + } catch (SecurityException e) { + throw new AssertionError(e); + } catch (NoSuchFieldException e) { + throw new AssertionError(e); + } + } + /** * Gets the {@link FilePath} representation of the "~" directory * (User's home directory in the Unix sense) of the given channel. diff --git a/core/src/main/java/hudson/org/apache/tools/tar/TarInputStream.java b/core/src/main/java/hudson/org/apache/tools/tar/TarInputStream.java index d7d8a5b54d..f2d10c1c39 100644 --- a/core/src/main/java/hudson/org/apache/tools/tar/TarInputStream.java +++ b/core/src/main/java/hudson/org/apache/tools/tar/TarInputStream.java @@ -37,9 +37,8 @@ import java.io.ByteArrayOutputStream; * methods are provided to position at each successive entry in * the archive, and the read each entry as a normal input stream * using read(). - * @deprecated Use {@link org.apache.commons.compress.archivers.tar.TarArchiveInputStream} instead + * */ -@Deprecated public class TarInputStream extends FilterInputStream { // CheckStyle:VisibilityModifier OFF - bc diff --git a/core/src/main/java/hudson/org/apache/tools/tar/TarOutputStream.java b/core/src/main/java/hudson/org/apache/tools/tar/TarOutputStream.java index 48f4876bd4..f23e442628 100644 --- a/core/src/main/java/hudson/org/apache/tools/tar/TarOutputStream.java +++ b/core/src/main/java/hudson/org/apache/tools/tar/TarOutputStream.java @@ -35,11 +35,8 @@ import java.io.IOException; * The TarOutputStream writes a UNIX tar archive as an OutputStream. * Methods are provided to put entries, and then write their contents * by writing to this stream using write(). - * - * @deprecated Use {@link org.apache.commons.compress.archivers.tar.TarArchiveOutputStream} instead * */ -@Deprecated public class TarOutputStream extends FilterOutputStream { /** Fail if a long file name is required in the archive. */ public static final int LONGFILE_ERROR = 0; diff --git a/core/src/main/java/hudson/util/io/TarArchiver.java b/core/src/main/java/hudson/util/io/TarArchiver.java index 4cfa5ce987..7e7a3dd4f0 100644 --- a/core/src/main/java/hudson/util/io/TarArchiver.java +++ b/core/src/main/java/hudson/util/io/TarArchiver.java @@ -37,8 +37,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.Field; -import org.apache.commons.compress.archivers.tar.TarArchiveEntry; -import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import static org.apache.tools.tar.TarConstants.LF_SYMLINK; @@ -49,10 +47,10 @@ import static org.apache.tools.tar.TarConstants.LF_SYMLINK; */ final class TarArchiver extends Archiver { private final byte[] buf = new byte[8192]; - private final TarArchiveOutputStream tar; + private final TarOutputStream tar; TarArchiver(OutputStream out) { - tar = new TarArchiveOutputStream(new BufferedOutputStream(out) { + tar = new TarOutputStream(new BufferedOutputStream(out) { // TarOutputStream uses TarBuffer internally, // which flushes the stream for each block. this creates unnecessary // data stream fragmentation, and flush request to a remote, which slows things down. @@ -60,14 +58,13 @@ final class TarArchiver extends Archiver { public void flush() throws IOException { // so don't do anything in flush } - }); - tar.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_STAR); - tar.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU); + }); + tar.setLongFileMode(TarOutputStream.LONGFILE_GNU); } @Override public void visitSymlink(File link, String target, String relativePath) throws IOException { - TarArchiveEntry e = new TarArchiveEntry(relativePath, LF_SYMLINK); + TarEntry e = new TarEntry(relativePath, LF_SYMLINK); try { int mode = IOUtils.mode(link); if (mode != -1) { @@ -76,11 +73,16 @@ final class TarArchiver extends Archiver { } catch (PosixException x) { // ignore } - - e.setLinkName(target); - tar.putArchiveEntry(e); - tar.closeArchiveEntry(); + try { + StringBuffer linkName = (StringBuffer) LINKNAME_FIELD.get(e); + linkName.setLength(0); + linkName.append(target); + } catch (IllegalAccessException x) { + throw new IOException("Failed to set linkName", x); + } + + tar.putNextEntry(e); entriesWritten++; } @@ -95,14 +97,14 @@ final class TarArchiver extends Archiver { if(file.isDirectory()) relativePath+='/'; - TarArchiveEntry te = new TarArchiveEntry(relativePath); + TarEntry te = new TarEntry(relativePath); int mode = IOUtils.mode(file); if (mode!=-1) te.setMode(mode); te.setModTime(file.lastModified()); if(!file.isDirectory()) te.setSize(file.length()); - tar.putArchiveEntry(te); + tar.putNextEntry(te); if (!file.isDirectory()) { FileInputStream in = new FileInputStream(file); @@ -115,11 +117,25 @@ final class TarArchiver extends Archiver { } } - tar.closeArchiveEntry(); + tar.closeEntry(); entriesWritten++; } public void close() throws IOException { tar.close(); } + + private static final Field LINKNAME_FIELD = getTarEntryLinkNameField(); + + private static Field getTarEntryLinkNameField() { + try { + Field f = TarEntry.class.getDeclaredField("linkName"); + f.setAccessible(true); + return f; + } catch (SecurityException e) { + throw new AssertionError(e); + } catch (NoSuchFieldException e) { + throw new AssertionError(e); + } + } }