| /******************************************************************************* |
| * Copyright (c) 2007, 2019 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Red Hat Inc. - Bug 460967 |
| * SAP SE - bug 465602 |
| *******************************************************************************/ |
| package org.eclipse.equinox.internal.p2.touchpoint.natives; |
| |
| import java.io.*; |
| import java.net.URI; |
| import java.util.*; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| import java.util.zip.ZipEntry; |
| import java.util.zip.ZipInputStream; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.equinox.internal.p2.core.helpers.LogHelper; |
| import org.eclipse.equinox.p2.core.*; |
| import org.eclipse.equinox.p2.engine.IProfile; |
| import org.eclipse.equinox.p2.repository.IRepository; |
| import org.eclipse.equinox.p2.repository.artifact.*; |
| import org.eclipse.osgi.util.NLS; |
| |
| public class Util { |
| |
| public static void log(String message) { |
| LogHelper.log(createError(message)); |
| } |
| |
| public static IStatus createError(String message) { |
| return new Status(IStatus.ERROR, Activator.ID, message); |
| } |
| |
| public static IStatus createError(String message, Throwable exception) { |
| return new Status(IStatus.ERROR, Activator.ID, message, exception); |
| } |
| |
| public static String getInstallFolder(IProfile profile) { |
| return profile.getProperty(IProfile.PROP_INSTALL_FOLDER); |
| } |
| |
| private static IAgentLocation getAgentLocation(IProvisioningAgent agent) { |
| return agent.getService(IAgentLocation.class); |
| } |
| |
| public static IArtifactRepositoryManager getArtifactRepositoryManager(IProvisioningAgent agent) { |
| return agent.getService(IArtifactRepositoryManager.class); |
| } |
| |
| public static IFileArtifactRepository getDownloadCacheRepo(IProvisioningAgent agent) throws ProvisionException { |
| URI location = getDownloadCacheLocation(agent); |
| if (location == null) |
| throw new IllegalStateException(Messages.could_not_obtain_download_cache); |
| IArtifactRepositoryManager manager = getArtifactRepositoryManager(agent); |
| if (manager == null) |
| throw new IllegalStateException(Messages.artifact_repo_not_found); |
| IArtifactRepository repository; |
| try { |
| repository = manager.loadRepository(location, null); |
| } catch (ProvisionException e) { |
| // the download cache doesn't exist or couldn't be read. Create new cache. |
| String repositoryName = location + " - Agent download cache"; //$NON-NLS-1$ |
| Map<String, String> properties = new HashMap<>(1); |
| properties.put(IRepository.PROP_SYSTEM, Boolean.TRUE.toString()); |
| repository = manager.createRepository(location, repositoryName, |
| IArtifactRepositoryManager.TYPE_SIMPLE_REPOSITORY, properties); |
| } |
| |
| IFileArtifactRepository downloadCache = repository.getAdapter(IFileArtifactRepository.class); |
| if (downloadCache == null) |
| throw new ProvisionException(NLS.bind(Messages.download_cache_not_writeable, location)); |
| return downloadCache; |
| } |
| |
| static private URI getDownloadCacheLocation(IProvisioningAgent agent) { |
| IAgentLocation location = getAgentLocation(agent); |
| if (location == null) |
| return null; |
| return URIUtil.append(location.getDataArea("org.eclipse.equinox.p2.core"), "cache/"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| /** |
| * Unzip from a File to an output directory, with progress indication and |
| * backup. monitor and backup store may be null. |
| */ |
| public static File[] unzipFile(File zipFile, File outputDir, IBackupStore store, String taskName, |
| IProgressMonitor monitor) throws IOException { |
| return unzipFile(zipFile, outputDir, null /* path */, null /* includes */, null /* excludes */, store, taskName, |
| monitor); |
| } |
| |
| /** |
| * Unzip from a File to an output directory, with progress indication and |
| * backup. monitor and backup store may be null. It takes in count |
| * exclude/exclude pattern (that can be null, case when everything is unzipped). |
| * If a path is specified, the path is consider as entry point in zip, as when |
| * the to directory in zip would have been the specified path. |
| */ |
| public static File[] unzipFile(File zipFile, File outputDir, String path, String[] includePatterns, |
| String[] excludePatterns, IBackupStore store, String taskName, IProgressMonitor monitor) |
| throws IOException { |
| try (InputStream in = new FileInputStream(zipFile)) { |
| return unzipStream(in, zipFile.length(), outputDir, path, includePatterns, excludePatterns, store, taskName, |
| monitor); |
| } catch (IOException e) { |
| // add the file name to the message |
| IOException ioException = new IOException(NLS.bind(Messages.Util_Error_Unzipping, zipFile, e.getMessage())); |
| ioException.initCause(e); |
| throw ioException; |
| } |
| } |
| |
| /** |
| * Unzip from an InputStream to an output directory using backup of overwritten |
| * files if backup store is not null. |
| */ |
| public static File[] unzipStream(InputStream stream, long size, File outputDir, IBackupStore store, String taskName, |
| IProgressMonitor monitor) throws IOException { |
| return unzipStream(stream, size, outputDir, null /* path */, null /* includes */, null /* excludes */, store, |
| taskName, monitor); |
| } |
| |
| /** |
| * Unzip from an InputStream to an output directory using backup of overwritten |
| * files if backup store is not null. It takes in count exclude/exclude pattern |
| * (that can be null, case when everything is unzipped). If a path is specified, |
| * the path is consider as entry point in zip, as when the to directory in zip |
| * would have been the specified path. |
| */ |
| public static File[] unzipStream(InputStream stream, long size, File outputDir, String path, |
| String[] includePatterns, String[] excludePatterns, IBackupStore store, String taskName, |
| IProgressMonitor monitor) throws IOException { |
| InputStream is = monitor == null ? stream : stream; // new ProgressMonitorInputStream(stream, size, size, |
| // taskName, monitor); TODO Commented code |
| try (ZipInputStream in = new ZipInputStream(new BufferedInputStream(is))) { |
| ZipEntry ze = in.getNextEntry(); |
| if (ze == null) { |
| // There must be at least one entry in a zip file. |
| // When there isn't getNextEntry returns null. |
| in.close(); |
| throw new IOException(Messages.Util_Invalid_Zip_File_Format); |
| } |
| |
| if (path != null && path.trim().length() == 0) |
| path = null; |
| Pattern pathRegex = path == null ? null : createAntStylePattern("(" + path + ")(*)"); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| Collection<Pattern> includeRegexp = new ArrayList<>(); |
| Collection<Pattern> excludeRegexp = new ArrayList<>(); |
| if (includePatterns != null) { |
| for (String pattern : includePatterns) { |
| if (pattern != null) { |
| includeRegexp.add(createAntStylePattern(pattern)); |
| } |
| } |
| } |
| if (excludePatterns != null) { |
| for (String pattern : excludePatterns) { |
| if (pattern != null) { |
| excludeRegexp.add(createAntStylePattern(pattern)); |
| } |
| } |
| } |
| ArrayList<File> unzippedFiles = new ArrayList<>(); |
| do { |
| String name = ze.getName(); |
| if (pathRegex == null || pathRegex.matcher(name).matches()) { |
| boolean unzip = includeRegexp.isEmpty(); |
| for (Pattern pattern : includeRegexp) { |
| unzip = pattern.matcher(name).matches(); |
| if (unzip) |
| break; |
| } |
| if (unzip && !excludeRegexp.isEmpty()) { |
| for (Pattern pattern : excludeRegexp) { |
| if (pattern.matcher(name).matches()) { |
| unzip = false; |
| break; |
| } |
| } |
| } |
| if (unzip) { |
| if (pathRegex != null) { |
| Matcher matcher = pathRegex.matcher(name); |
| if (matcher.matches()) { |
| name = matcher.group(2); |
| if (name.startsWith("/")) //$NON-NLS-1$ |
| name = name.substring(1); |
| } |
| } |
| File outFile = createSubPathFile(outputDir, name); |
| unzippedFiles.add(outFile); |
| if (ze.isDirectory()) { |
| outFile.mkdirs(); |
| } else { |
| if (outFile.exists()) { |
| if (store != null) |
| store.backup(outFile); |
| else |
| outFile.delete(); |
| } else { |
| outFile.getParentFile().mkdirs(); |
| } |
| try { |
| copyStream(in, false, new FileOutputStream(outFile), true); |
| } catch (FileNotFoundException e) { |
| // TEMP: ignore this for now in case we're trying to replace |
| // a running eclipse.exe |
| // TODO: This is very questionable as it will shadow any other |
| // issue with extraction!! |
| } |
| outFile.setLastModified(ze.getTime()); |
| } |
| } |
| } |
| in.closeEntry(); |
| } while ((ze = in.getNextEntry()) != null); |
| return unzippedFiles.toArray(new File[unzippedFiles.size()]); |
| } |
| |
| } |
| |
| private static File createSubPathFile(File root, String subPath) throws IOException { |
| File result = new File(root, subPath).getCanonicalFile(); |
| String resultCanonical = result.getPath(); |
| String rootCanonical = root.getCanonicalPath(); |
| if (!resultCanonical.startsWith(rootCanonical + File.separator) && !resultCanonical.equals(rootCanonical)) { |
| throw new IOException("Invalid path: " + subPath); //$NON-NLS-1$ |
| } |
| return result; |
| } |
| |
| /** |
| * Copy an input stream to an output stream. Optionally close the streams when |
| * done. Return the number of bytes written. |
| */ |
| public static int copyStream(InputStream in, boolean closeIn, OutputStream out, boolean closeOut) |
| throws IOException { |
| try { |
| int written = 0; |
| byte[] buffer = new byte[16 * 1024]; |
| int len; |
| while ((len = in.read(buffer)) != -1) { |
| out.write(buffer, 0, len); |
| written += len; |
| } |
| return written; |
| } finally { |
| try { |
| if (closeIn) { |
| in.close(); |
| } |
| } finally { |
| if (closeOut) { |
| out.close(); |
| } |
| } |
| } |
| } |
| |
| private static Pattern createAntStylePattern(String pattern) { |
| StringBuffer sb = new StringBuffer(); |
| for (int c = 0; c < pattern.length(); c++) { |
| switch (pattern.charAt(c)) { |
| case '.': |
| sb.append("\\."); //$NON-NLS-1$ |
| break; |
| case '*': |
| sb.append(".*"); //$NON-NLS-1$ |
| break; |
| case '?': |
| sb.append(".?"); //$NON-NLS-1$ |
| break; |
| default: |
| sb.append(pattern.charAt(c)); |
| break; |
| } |
| } |
| String string = sb.toString(); |
| if (string.endsWith("\\..*")) { //$NON-NLS-1$ |
| sb.append("|"); //$NON-NLS-1$ |
| sb.append(string.substring(0, string.length() - 4)); |
| } |
| return Pattern.compile(sb.toString()); |
| } |
| |
| } |