/******************************************************************************* * Copyright (c) 2014 Mentor Graphics 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: * Mentor Graphics - initial API and implementation *******************************************************************************/ package com.codesourcery.internal.installer; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.text.MessageFormat; import java.util.UUID; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import com.codesourcery.installer.AbstractInstallVerifier; import com.codesourcery.installer.IInstallComponent; import com.codesourcery.installer.IInstallDescription; import com.codesourcery.installer.IInstallMode; import com.codesourcery.installer.IInstallProduct; import com.codesourcery.installer.IProductRange; import com.codesourcery.installer.Installer; /** * General installation verifier. */ public class GeneralInstallVerifier extends AbstractInstallVerifier { /** * Constructor */ public GeneralInstallVerifier() { } /** * Checks if the install location is empty. * * @param location Install location. * @param manifest Install manifest. * @return <code>IStatus.OK</code> if location is empty. */ private IStatus checkEmpty(IPath location, InstallManifest manifest) { IStatus status = Status.OK_STATUS; boolean productsFound = ((manifest != null) && (manifest.getProducts().length > 0)); boolean installationFound = false; if (RepositoryManager.getDefault().getAgent() != null) { if (location.isPrefixOf(RepositoryManager.getDefault().getAgentLocation())) { installationFound = true; } } // If no existing products are found at the location and installation has not been already initialized // in location. if (!productsFound && !installationFound) { if ((location != null) && location.toFile().exists() && (location.toFile().list().length > 0)) { String errorMessage = MessageFormat.format(InstallMessages.Error_NonEmptyInstallLocation0, location.toOSString()); status = new Status(IStatus.ERROR, Installer.ID, errorMessage); } } return status; } /** * Checks permissions for the install location. * * @param location Location. * @return <code>IStatus.OK</code> if location is writable. */ private IStatus checkPermissions(IPath location) { IStatus status = Status.OK_STATUS; File directory = location.toFile(); if (directory.exists()) { IInstallMode installMode = Installer.getDefault().getInstallManager().getInstallMode(); if (installMode.isInstall() && !installMode.isUpdate() && !installMode.isUpgrade()) { // Check write permissions if (!Files.isWritable(directory.toPath())) { status = new Status(IStatus.ERROR, Installer.ID, InstallMessages.NoWritePermissions); } // Check read permissions else if (!Files.isReadable(directory.toPath())) { status = new Status(IStatus.ERROR, Installer.ID, InstallMessages.NoWritePermissions); } // If that succeeds, check if a file really can be written (Windows permissions). else { // File.canWrite() can't be used as it does not check Windows security permissions // Files.isWriteable() can't be used. Although it checks Windows security permissions, it // is unreliable (fixed only in Java 8 (b84) and back-ported to Java 7u40). File tempFile = location.append(UUID.randomUUID().toString()).toFile(); try { if (tempFile.createNewFile()) { tempFile.delete(); } } catch (IOException e) { status = new Status(IStatus.ERROR, Installer.ID, InstallMessages.NoWritePermissions); } } } } return status; } /** * Checks for required installed products. * * @param manifest Install manifest. * @param ranges Ranges for installed products. * @return <code>IStatus.ERROR</code> if no product is installed for the required range. */ private IStatus checkProductRanges(InstallManifest manifest, IProductRange[] ranges) { IStatus status = Status.OK_STATUS; IInstallProduct[] matchedProducts = null; if (manifest != null) { matchedProducts = manifest.getProducts(ranges); } // No products found that match required ranges if ((matchedProducts == null) || (matchedProducts.length == 0)) { status = new Status(IStatus.ERROR, Installer.ID, InstallMessages.Error_ProductsNotFound); } return status; } /** * Checks for an existing installed version of the product. * * @param installDescription Install description * @param manifest Install manifest * @return <code>IStatus.ERROR</code> if an existing version of the product is already installed. */ private IStatus checkExistingVersion(IInstallDescription installDescription, InstallManifest manifest) { IStatus status = Status.OK_STATUS; IInstallMode installMode = Installer.getDefault().getInstallManager().getInstallMode(); if ((manifest != null) && !installMode.isUpdate()) { IInstallProduct product = Installer.getDefault().getInstallManager().getExistingProduct(manifest); if (product != null) { // Same or newer version installed if ((product.getVersion().compareTo(installDescription.getProductVersion()) == 0) || (product.getVersion().compareTo(installDescription.getProductVersion()) > 0)) { String errorMessage = MessageFormat.format(InstallMessages.Error_AlreadyInstalled1, new Object[] { installDescription.getProductName(), product.getVersionString() }); status = new Status(IStatus.ERROR, Installer.ID, errorMessage); } // Older version installed else if (product.getVersion().compareTo(installDescription.getProductVersion()) < 0) { boolean upgradeSupported = true; // Upgrade supported if (installDescription.getSupportsUpgrade()) { if (installDescription.getMinimumUpgradeVersion() != null) { upgradeSupported = product.getVersion().compareTo(installDescription.getMinimumUpgradeVersion()) >= 0; } } // Upgrade not supported else { upgradeSupported = false; } if (upgradeSupported) { String errorMessage = MessageFormat.format(InstallMessages.Error_Upgrade2, new Object[] { installDescription.getProductName(), product.getVersionString(), installDescription.getProductVersionString() }); status = new Status(IStatus.WARNING, Installer.ID, errorMessage); } else { String errorMessage = MessageFormat.format(InstallMessages.Error_NoUpgrade1, new Object[] { installDescription.getProductName(), product.getVersionString() }); status = new Status(IStatus.ERROR, Installer.ID, errorMessage); } } } } return status; } @Override public IStatus verifyInstallLocation(IPath location) { IStatus status = Status.OK_STATUS; try { IInstallDescription installDescription = Installer.getDefault().getInstallManager().getInstallDescription(); InstallManifest manifest = InstallManifest.loadManifest(location); // No location specified if (location.isEmpty()) { status = new Status(IStatus.ERROR, Installer.ID, InstallMessages.Error_PleaseSpecifyLocation); } // Check if install location is required to be empty if (status.isOK() && installDescription.getRequireEmptyInstallDirectory()) { status = checkEmpty(location, manifest); } // Requirement on existing products if (status.isOK()) { IProductRange[] ranges = installDescription.getRequires(); if (ranges != null) { status = checkProductRanges(manifest, ranges); } // Check for existing version of install product else { status = checkExistingVersion(installDescription, manifest); } } // Check that the install location is writable if (status.isOK()) { status = checkPermissions(location); } } catch (CoreException e) { Installer.log(e); } return status; } @Override public IStatus verifyInstallComponentSelection( IInstallComponent[] selectedComponents) { // For new installation, at least one component must be selected if (!Installer.getDefault().getInstallManager().getInstallMode().isUpdate() && (selectedComponents.length == 0)) { return new Status(IStatus.ERROR, Installer.ID, InstallMessages.Error_SelectAtLeastOneComponent); } return Status.OK_STATUS; } }