/************************************************************************************* * Copyright (c) 2014 Red Hat, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * JBoss by Red Hat - Initial implementation. ************************************************************************************/ package org.jboss.tools.runtime.core.extract.internal; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.osgi.util.NLS; import org.jboss.tools.runtime.core.RuntimeCoreActivator; import org.jboss.tools.runtime.core.extract.IOverwrite; import org.jboss.tools.runtime.core.extract.internal.xpl.TarEntry; import org.jboss.tools.runtime.core.extract.internal.xpl.TarInputStream; public class UntarUtility implements IExtractUtility { private static final String SEPARATOR = "/"; //$NON-NLS-1$ protected File file; private String discoveredRoot = null; private boolean rootEntryImpossible = false; public UntarUtility(File file) { this.file = file; } private byte[] BUFFER = null; public IStatus extract(File destination, IOverwrite overwriteQuery, IProgressMonitor monitor) throws CoreException { FileInputStream in = null; try { in = new FileInputStream(file); untar(in, new Path(destination.getAbsolutePath()), monitor); } catch(IOException ioe) { throw new CoreException(new Status(IStatus.ERROR, RuntimeCoreActivator.PLUGIN_ID, 0, NLS.bind("Error extracting runtime", ioe.getLocalizedMessage()), ioe)); } finally { try { if (in != null) in.close(); } catch (IOException e) { // ignore } monitor.done(); } return null; } protected void untar(InputStream in, IPath path, IProgressMonitor monitor) throws IOException { String possibleRoot = null; int fileCnt = -1; SubMonitor progress = SubMonitor.convert(monitor, (fileCnt > 0) ? fileCnt : 500); String archivePath = null; BufferedInputStream bin = new BufferedInputStream(in); TarInputStream zin = new TarInputStream(bin); TarEntry entry = zin.getNextEntry(); while (entry != null) { String name = entry.getName(); progress.subTask(NLS.bind("Uncompressing {0}", name)); if (archivePath != null && name.startsWith(archivePath)) { name = name.substring(archivePath.length()); if (name.length() > 1) name = name.substring(1); } if (name != null && name.length() > 0) { if (entry.getFileType() == TarEntry.DIRECTORY) path.append(name).toFile().mkdirs(); else { File dir = path.append(name).removeLastSegments(1).toFile(); if (!dir.exists()) dir.mkdirs(); FileOutputStream fout = new FileOutputStream(path.append(name).toFile()); copyWithSize(zin, fout, progress.newChild(1), (int)entry.getSize()); fout.close(); if (fileCnt <= 0) progress.setWorkRemaining(500); } } // Lets check for a possible root, to avoid scanning the archive again later if( !rootEntryImpossible && discoveredRoot == null) { // Check for a root if (name == null || name.isEmpty() || name.startsWith(SEPARATOR) || name.indexOf(SEPARATOR) == -1) { rootEntryImpossible = true; possibleRoot = null; } else { String directory = name.substring(0, name.indexOf(SEPARATOR)); if (possibleRoot == null) { possibleRoot = directory; } else if (!directory.equals(possibleRoot)) { rootEntryImpossible = true; possibleRoot = null; } } } entry = zin.getNextEntry(); } this.discoveredRoot = possibleRoot; zin.close(); } protected void copyWithSize(InputStream in, OutputStream out, IProgressMonitor monitor, int size) throws IOException { if (BUFFER == null) BUFFER = new byte[8192]; SubMonitor progress = SubMonitor.convert(monitor, size); int r = in.read(BUFFER); while (r >= 0) { out.write(BUFFER, 0, r); progress.worked(r); r = in.read(BUFFER); } } public String getRoot(IProgressMonitor monitor) throws CoreException { // IF we found a root during the extract, use that. if( discoveredRoot != null ) return discoveredRoot; if( rootEntryImpossible) return null; // We don't have the .tar file anymore, so can't analyze it. return null; } }