1 /*******************************************************************************
2  *  Copyright (c) 2007, 2017 IBM Corporation and others.
3  *
4  *  This program and the accompanying materials
5  *  are made available under the terms of the Eclipse Public License 2.0
6  *  which accompanies this distribution, and is available at
7  *  https://www.eclipse.org/legal/epl-2.0/
8  *
9  *  SPDX-License-Identifier: EPL-2.0
10  *
11  *  Contributors:
12  *     IBM Corporation - initial API and implementation
13  *     Red Hat, Inc - fragments support added
14  *******************************************************************************/
15 package org.eclipse.equinox.internal.p2.engine;
16 
17 import java.io.*;
18 import java.net.URI;
19 import java.net.URISyntaxException;
20 import java.nio.file.Files;
21 import java.util.*;
22 import org.eclipse.core.runtime.IStatus;
23 import org.eclipse.core.runtime.Status;
24 import org.eclipse.equinox.internal.p2.core.helpers.LogHelper;
25 import org.eclipse.osgi.util.NLS;
26 import org.osgi.framework.BundleActivator;
27 import org.osgi.framework.BundleContext;
28 
29 public class EngineActivator implements BundleActivator {
30 	private static BundleContext context;
31 	/**
32 	 * as for now it is exactly the same variable as in simpleconfigurator Activator
33 	 * @noreference This field is not intended to be referenced by clients.
34 	 */
35 	public static String EXTENSIONS = System.getProperty("p2.fragments"); //$NON-NLS-1$
36 	public static boolean EXTENDED = EXTENSIONS != null;
37 	private static final String LINK_KEY = "link"; //$NON-NLS-1$
38 	private static final String LINK_FILE_EXTENSION = ".link"; //$NON-NLS-1$
39 	private static final Set<File> reportedExtensions = Collections.synchronizedSet(new HashSet<File>(0));
40 
41 	public static final String ID = "org.eclipse.equinox.p2.engine"; //$NON-NLS-1$
42 
43 	/**
44 	 * System property describing the profile registry file format
45 	 */
46 	public static final String PROP_PROFILE_FORMAT = "eclipse.p2.profileFormat"; //$NON-NLS-1$
47 
48 	/**
49 	 * Value for the PROP_PROFILE_FORMAT system property specifying raw XML file
50 	 * format (used in p2 until and including 3.5.0 release).
51 	 */
52 	public static final String PROFILE_FORMAT_UNCOMPRESSED = "uncompressed"; //$NON-NLS-1$
53 
54 	/**
55 	 * System property specifying how the engine should handle unsigned artifacts.
56 	 * If this property is undefined, the default value is assumed to be "prompt".
57 	 */
58 	public static final String PROP_UNSIGNED_POLICY = "eclipse.p2.unsignedPolicy"; //$NON-NLS-1$
59 
60 	/**
61 	 * System property value specifying that the engine should prompt for confirmation
62 	 * when installing unsigned artifacts.
63 	 */
64 	public static final String UNSIGNED_PROMPT = "prompt"; //$NON-NLS-1$
65 
66 	/**
67 	 * System property value specifying that the engine should fail when an attempt
68 	 * is made to install unsigned artifacts.
69 	 */
70 	public static final String UNSIGNED_FAIL = "fail"; //$NON-NLS-1$
71 
72 	/**
73 	 * System property value specifying that the engine should silently allow unsigned
74 	 * artifacts to be installed.
75 	 */
76 	public static final String UNSIGNED_ALLOW = "allow"; //$NON-NLS-1$
77 
getContext()78 	public static BundleContext getContext() {
79 		return context;
80 	}
81 
82 	/**
83 	 * This property indicates repositories that are passed via the fragments mechanism.
84 	 */
85 	public static final String P2_FRAGMENT_PROPERTY = "p2.fragment"; //$NON-NLS-1$
86 
87 	@Override
start(BundleContext aContext)88 	public void start(BundleContext aContext) throws Exception {
89 		EngineActivator.context = aContext;
90 	}
91 
92 	@Override
stop(BundleContext aContext)93 	public void stop(BundleContext aContext) throws Exception {
94 		EngineActivator.context = null;
95 	}
96 
getExtensionsDirectories()97 	public static File[] getExtensionsDirectories() {
98 		List<File> files = new ArrayList<>(0);
99 		if (EXTENSIONS != null) {
100 			String[] locationToCheck = EXTENSIONS.split(","); //$NON-NLS-1$
101 			for (String location : locationToCheck) {
102 				try {
103 					files.addAll(getInfoFilesFromLocation(location));
104 				} catch (FileNotFoundException e) {
105 					LogHelper.log(new Status(IStatus.ERROR, ID, NLS.bind(Messages.EngineActivator_0, location), e));
106 				} catch (IOException e) {
107 					LogHelper.log(new Status(IStatus.ERROR, ID, NLS.bind(Messages.EngineActivator_0, location), e));
108 				} catch (URISyntaxException e) {
109 					LogHelper.log(new Status(IStatus.ERROR, ID, NLS.bind(Messages.EngineActivator_0, location), e));
110 				}
111 			}
112 		}
113 		return files.toArray(new File[files.size()]);
114 	}
115 
116 	// This method must match the implementation in the SimpleConfiguratorUtils with the only difference that
117 	// parent folder of the metadata is returned.
getInfoFilesFromLocation(String locationToCheck)118 	private static ArrayList<File> getInfoFilesFromLocation(String locationToCheck) throws IOException, FileNotFoundException, URISyntaxException {
119 		ArrayList<File> result = new ArrayList<>(1);
120 
121 		File extensionsLocation = new File(locationToCheck);
122 
123 		if (extensionsLocation.exists() && extensionsLocation.isDirectory()) {
124 			//extension location contains extensions
125 			File[] extensions = extensionsLocation.listFiles();
126 			for (File extension : extensions) {
127 				if (extension.isFile() && extension.getName().endsWith(LINK_FILE_EXTENSION)) {
128 					Properties link = new Properties();
129 					link.load(new FileInputStream(extension));
130 					String newInfoName = link.getProperty(LINK_KEY);
131 					URI newInfoURI = new URI(newInfoName);
132 					File newInfoFile = null;
133 					if (newInfoURI.isAbsolute()) {
134 						newInfoFile = new File(newInfoName);
135 					} else {
136 						newInfoFile = new File(extension.getParentFile(), newInfoName);
137 					}
138 					if (newInfoFile.exists()) {
139 						extension = newInfoFile.getParentFile();
140 					}
141 				}
142 
143 				if (extension.isDirectory()) {
144 					if (Files.isWritable(extension.toPath())) {
145 						synchronized (reportedExtensions) {
146 							if (!reportedExtensions.contains(extension)) {
147 								reportedExtensions.add(extension);
148 								LogHelper.log(new Status(IStatus.ERROR, ID, NLS.bind(Messages.EngineActivator_1, extension)));
149 							}
150 						}
151 						continue;
152 					}
153 					File[] listFiles = extension.listFiles();
154 					// new magic - multiple info files, f.e.
155 					//   egit.info (git feature)
156 					//   cdt.link (properties file containing link=path) to other info file
157 					for (File file : listFiles) {
158 						//if it is a info file - load it
159 						if (file.getName().endsWith(".info")) { //$NON-NLS-1$
160 							result.add(extension);
161 						}
162 						// if it is a link - dereference it
163 					}
164 				} else {
165 					synchronized (reportedExtensions) {
166 						if (!reportedExtensions.contains(extension)) {
167 							reportedExtensions.add(extension);
168 							LogHelper.log(new Status(IStatus.WARNING, ID, NLS.bind(Messages.EngineActivator_3, extension)));
169 						}
170 					}
171 				}
172 			}
173 		}
174 		return result;
175 	}
176 }
177