Merge content from HEAD (tag v20100730)
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/protocol/MultiplexingFactory.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/protocol/MultiplexingFactory.java
index f0f2c46..1d06aba 100644
--- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/protocol/MultiplexingFactory.java
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/protocol/MultiplexingFactory.java
@@ -12,7 +12,6 @@
 import java.util.*;
 import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor;
 import org.eclipse.osgi.framework.internal.core.AbstractBundle;
-import org.eclipse.osgi.framework.internal.core.Framework;
 import org.eclipse.osgi.framework.log.FrameworkLogEntry;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
@@ -54,32 +53,24 @@
 
 	abstract public Object getParentFactory();
 
-	public synchronized boolean isMultiplexing() {
-		return factories != null || composites != null;
+	public boolean isMultiplexing() {
+		return getFactories() != null || getComposites() != null;
 	}
 
-	public synchronized void registerComposite(MultiplexingFactory compositeFactory) {
-		if (composites == null)
-			composites = new LinkedList<MultiplexingFactory>();
-		compositeFactory.setParentFactory(getParentFactory());
-		composites.add(compositeFactory);
+	public void registerComposite(MultiplexingFactory compositeFactory) {
+		addComposite(compositeFactory);
 		// always reset the handers so we can force in multiplexing ones
 		resetHandlers();
 	}
 
 	protected abstract void resetHandlers();
 
-	public synchronized void unregisterComposite(MultiplexingFactory compositeFactory) {
-		composites.remove(compositeFactory);
-		if (composites.isEmpty())
-			composites = null;
+	public void unregisterComposite(MultiplexingFactory compositeFactory) {
+		removeComposite(compositeFactory);
 		compositeFactory.closePackageAdminTracker();
 	}
 
-	public synchronized void register(Object factory) {
-		if (factories == null)
-			factories = new LinkedList();
-
+	public void register(Object factory) {
 		// set parent for each factory so they can do proper delegation
 		try {
 			Class clazz = factory.getClass();
@@ -89,19 +80,13 @@
 			adaptor.getFrameworkLog().log(new FrameworkLogEntry(MultiplexingFactory.class.getName(), FrameworkLogEntry.ERROR, 0, "register", FrameworkLogEntry.ERROR, e, null)); //$NON-NLS-1$
 			throw new RuntimeException(e.getMessage(), e);
 		}
-		factories.add(factory);
+		addFactory(factory);
 		// always reset the handers so we can force in multiplexing ones
-		try {
-			Framework.resetURLStreamHandlers();
-		} catch (IllegalAccessException e) {
-			// TODO log
-		}
+		resetHandlers();
 	}
 
-	public synchronized void unregister(Object factory) {
-		factories.remove(factory);
-		if (factories.isEmpty())
-			factories = null;
+	public void unregister(Object factory) {
+		removeFactory(factory);
 		// close the service tracker
 		try {
 			// this is brittle; if class does not directly extend MultplexingFactory then this method will not exist, but we do not want a public method here
@@ -114,23 +99,29 @@
 		}
 	}
 
-	public synchronized Object designateSuccessor() {
-		Object parentFactory = getParentFactory();
-		if (factories == null || factories.isEmpty())
-			return parentFactory;
-
-		Object successor = factories.remove(0);
+	public Object designateSuccessor() {
+		List released = releaseFactories();
+		// Note that we do this outside of the sync block above.
+		// This is only possible because we do additional locking outside of
+		// this class to ensure no other threads are trying to manipulate the
+		// list of registered factories.  See Framework class the following methods:
+		// Framework.installURLStreamHandlerFactory(BundleContext, FrameworkAdaptor)
+		// Framework.installContentHandlerFactory(BundleContext, FrameworkAdaptor)
+		// Framework.uninstallURLStreamHandlerFactory
+		// Framework.uninstallContentHandlerFactory()
+		if (released == null || released.isEmpty())
+			return getParentFactory();
+		Object successor = released.remove(0);
 		try {
 			Class clazz = successor.getClass();
 			Method register = clazz.getMethod("register", new Class[] {Object.class}); //$NON-NLS-1$		
-			for (Iterator it = factories.iterator(); it.hasNext();) {
+			for (Iterator it = released.iterator(); it.hasNext();) {
 				register.invoke(successor, new Object[] {it.next()});
 			}
 		} catch (Exception e) {
 			adaptor.getFrameworkLog().log(new FrameworkLogEntry(MultiplexingFactory.class.getName(), FrameworkLogEntry.ERROR, 0, "designateSuccessor", FrameworkLogEntry.ERROR, e, null)); //$NON-NLS-1$
 			throw new RuntimeException(e.getMessage(), e);
 		}
-		factories = null;
 		closePackageAdminTracker(); // close tracker
 		return successor;
 	}
@@ -139,7 +130,9 @@
 		packageAdminTracker.close();
 	}
 
-	public synchronized Object findAuthorizedFactory(List ignoredClasses) {
+	public Object findAuthorizedFactory(List ignoredClasses) {
+		List currentFactories = getFactories();
+		List<MultiplexingFactory> currentComposites = getComposites();
 		Class[] classStack = internalSecurityManager.getClassContext();
 		for (int i = 0; i < classStack.length; i++) {
 			Class clazz = classStack[i];
@@ -147,14 +140,14 @@
 				continue;
 			if (hasAuthority(clazz))
 				return this;
-			if (composites != null)
-				for (Iterator<MultiplexingFactory> iComposites = composites.iterator(); iComposites.hasNext();) {
+			if (currentComposites != null)
+				for (Iterator<MultiplexingFactory> iComposites = currentComposites.iterator(); iComposites.hasNext();) {
 					MultiplexingFactory composite = iComposites.next();
 					if (composite.hasAuthority(clazz))
 						return composite;
 				}
-			if (factories != null)
-				for (Iterator it = factories.iterator(); it.hasNext();) {
+			if (currentFactories != null)
+				for (Iterator it = currentFactories.iterator(); it.hasNext();) {
 					Object factory = it.next();
 					try {
 						Method hasAuthorityMethod = factory.getClass().getMethod("hasAuthority", new Class[] {Class.class}); //$NON-NLS-1$
@@ -193,8 +186,49 @@
 	 * Returns the composite id for this factory.  If this is not part of any composites -1 is returned.
 	 * @return the composite id for this factory
 	 */
-	protected synchronized long getCompositeId() {
-		return (composites == null && compositeId == 0) ? -1 : compositeId;
+	protected long getCompositeId() {
+		return (getComposites() == null && compositeId == 0) ? -1 : compositeId;
 
 	}
+
+	private synchronized List getFactories() {
+		return factories;
+	}
+
+	private synchronized List releaseFactories() {
+		if (factories == null)
+			return null;
+
+		List released = new LinkedList(factories);
+		factories = null;
+		return released;
+	}
+
+	private synchronized void addFactory(Object factory) {
+		List updated = (factories == null) ? new LinkedList() : new LinkedList(factories);
+		updated.add(factory);
+		factories = updated;
+	}
+
+	private synchronized void removeFactory(Object factory) {
+		List updated = new LinkedList(factories);
+		updated.remove(factory);
+		factories = updated.isEmpty() ? null : updated;
+	}
+
+	private synchronized List<MultiplexingFactory> getComposites() {
+		return composites;
+	}
+
+	private synchronized void addComposite(MultiplexingFactory composite) {
+		List<MultiplexingFactory> updated = (composites == null) ? new LinkedList<MultiplexingFactory>() : new LinkedList<MultiplexingFactory>(composites);
+		updated.add(composite);
+		composites = updated;
+	}
+
+	private synchronized void removeComposite(MultiplexingFactory composite) {
+		List<MultiplexingFactory> updated = new LinkedList<MultiplexingFactory>(composites);
+		updated.remove(composite);
+		composites = updated.isEmpty() ? null : updated;
+	}
 }
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/protocol/StreamHandlerFactory.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/protocol/StreamHandlerFactory.java
index d80739a..512e52c 100644
--- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/protocol/StreamHandlerFactory.java
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/protocol/StreamHandlerFactory.java
@@ -217,7 +217,7 @@
 	@Override
 	protected void resetHandlers() {
 		try {
-			((BundleContextImpl) context).getFramework().resetURLStreamHandlers();
+			Framework.resetURLStreamHandlers();
 		} catch (IllegalAccessException e) {
 			// TODO log
 		}
diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/DirBundleFile.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/DirBundleFile.java
index 3f8ee1d..1bf8643 100644
--- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/DirBundleFile.java
+++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/DirBundleFile.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * Copyright (c) 2005, 2010 IBM Corporation 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
@@ -37,33 +37,40 @@
 	}
 
 	public File getFile(String path, boolean nativeCode) {
-		File filePath = new File(this.basefile, path);
-		if (BundleFile.secureAction.exists(filePath)) {
-			return filePath;
+		boolean checkInBundle = path != null && path.indexOf("..") >= 0; //$NON-NLS-1$
+		File file = new File(basefile, path);
+		if (!BundleFile.secureAction.exists(file)) {
+			return null;
 		}
-		return null;
+		// must do an extra check to make sure file is within the bundle (bug 320546)
+		if (checkInBundle) {
+			try {
+				if (!BundleFile.secureAction.getCanonicalPath(file).startsWith(BundleFile.secureAction.getCanonicalPath(basefile)))
+					return null;
+			} catch (IOException e) {
+				return null;
+			}
+		}
+		return file;
 	}
 
 	public BundleEntry getEntry(String path) {
-		File filePath = new File(this.basefile, path);
-		if (!BundleFile.secureAction.exists(filePath)) {
+		File filePath = getFile(path, false);
+		if (filePath == null)
 			return null;
-		}
 		return new FileBundleEntry(filePath, path);
 	}
 
 	public boolean containsDir(String dir) {
-		File dirPath = new File(this.basefile, dir);
-		return BundleFile.secureAction.exists(dirPath) && BundleFile.secureAction.isDirectory(dirPath);
+		File dirPath = getFile(dir, false);
+		return dirPath != null && BundleFile.secureAction.isDirectory(dirPath);
 	}
 
 	public Enumeration getEntryPaths(String path) {
 		if (path.length() > 0 && path.charAt(0) == '/')
 			path = path.substring(1);
-		final java.io.File pathFile = new java.io.File(basefile, path);
-		if (!BundleFile.secureAction.exists(pathFile))
-			return null;
-		if (!BundleFile.secureAction.isDirectory(pathFile))
+		final File pathFile = getFile(path, false);
+		if (pathFile == null || !BundleFile.secureAction.isDirectory(pathFile))
 			return null;
 		final String[] fileList = BundleFile.secureAction.list(pathFile);
 		if (fileList == null || fileList.length == 0)
diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/GroupingChecker.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/GroupingChecker.java
index 79f9e59..9590d24 100644
--- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/GroupingChecker.java
+++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/GroupingChecker.java
@@ -15,10 +15,10 @@
  * The GroupingChecker checks the 'uses' directive on exported packages for consistency
  */
 public class GroupingChecker {
-	final PackageRoots nullPackageRoots = new PackageRoots(null, null);
+	final PackageRoots nullPackageRoots = new PackageRoots(null);
 	// a mapping of bundles to their package roots; keyed by
 	// ResolverBundle -> HashMap of packages; keyed by
-	// package name -> PackageRoots[]
+	// package name -> PackageRoots
 	private HashMap bundles = new HashMap();
 
 	/*
@@ -110,7 +110,7 @@
 			for (Iterator allImportingPackages = importingPackages.values().iterator(); allImportingPackages.hasNext();) {
 				PackageRoots roots = (PackageRoots) allImportingPackages.next();
 				if (roots != importingRoots)
-					results = roots.isConsistentClassSpace(exportingRoots, null, results);
+					results = roots.isConsistentClassSpace(exportingRoots, matchingExport.getExporter(), null, results);
 			}
 		return results;
 	}
@@ -193,7 +193,7 @@
 					return superSet;
 			}
 			// in this case we cannot share the package roots object; must create one specific for this bundle
-			PackageRoots result = new PackageRoots(packageName, bundle);
+			PackageRoots result = new PackageRoots(packageName);
 			// first merge all the roots from required bundles
 			for (int i = 0; i < requiredRoots.length; i++)
 				result.merge(requiredRoots[i]);
@@ -215,12 +215,10 @@
 
 	class PackageRoots {
 		private String name;
-		private ResolverBundle bundle;
 		private ResolverExport[] roots;
 
-		PackageRoots(String name, ResolverBundle bundle) {
+		PackageRoots(String name) {
 			this.name = name;
-			this.bundle = bundle;
 		}
 
 		public boolean hasRoots() {
@@ -298,7 +296,7 @@
 			return results;
 		}
 
-		public ArrayList isConsistentClassSpace(PackageRoots exportingRoots, ArrayList visited, ArrayList results) {
+		public ArrayList isConsistentClassSpace(PackageRoots exportingRoots, ResolverBundle exporter, ArrayList visited, ArrayList results) {
 			if (roots == null)
 				return results;
 			int size = roots.length;
@@ -316,7 +314,7 @@
 					if (uses[j].equals(root.getName()) || !uses[j].equals(exportingRoots.name))
 						continue;
 					PackageRoots thisUsedRoots = getPackageRoots(root.getExporter(), uses[j], null);
-					PackageRoots exportingUsedRoots = getPackageRoots(exportingRoots.bundle, uses[j], null);
+					PackageRoots exportingUsedRoots = getPackageRoots(exporter, uses[j], null);
 					if (thisUsedRoots == exportingRoots)
 						return results;
 					if (thisUsedRoots != nullPackageRoots && exportingUsedRoots != nullPackageRoots)
@@ -326,7 +324,7 @@
 							results.add(new PackageRoots[] {this, exportingUsedRoots});
 						}
 					// need to check the usedRoots consistency for transitive closure
-					results = thisUsedRoots.isConsistentClassSpace(exportingRoots, visited, results);
+					results = thisUsedRoots.isConsistentClassSpace(exportingRoots, exporter, visited, results);
 				}
 			}
 			return results;
diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateHelperImpl.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateHelperImpl.java
index 9a295c6..e4ee07b 100644
--- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateHelperImpl.java
+++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateHelperImpl.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2009 IBM Corporation and others.
+ * Copyright (c) 2004, 2010 IBM Corporation 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
@@ -559,9 +559,9 @@
 			for (int i = 0; i < fragments.length; i++) {
 				BundleSpecification[] fragmentRequiredBundles = fragments[i].getRequiredBundles();
 				for (int j = 0; j < fragmentRequiredBundles.length; j++) {
-					if (resolved.contains(fragmentRequiredBundles[i].getSupplier())) {
-						resolvedBundlesExported.put(fragmentRequiredBundles[i].getSupplier(), new Boolean(fragmentRequiredBundles[i].isExported()));
-						resolved.remove(fragmentRequiredBundles[i].getSupplier());
+					if (resolved.contains(fragmentRequiredBundles[j].getSupplier())) {
+						resolvedBundlesExported.put(fragmentRequiredBundles[j].getSupplier(), new Boolean(fragmentRequiredBundles[j].isExported()));
+						resolved.remove(fragmentRequiredBundles[j].getSupplier());
 					}
 				}
 				if (resolved.size() == 0) {
diff --git a/bundles/org.eclipse.osgi/supplement/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi/supplement/META-INF/MANIFEST.MF
index d8ff0de..7267dde7 100644
--- a/bundles/org.eclipse.osgi/supplement/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.osgi/supplement/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.equinox.supplement
-Bundle-Version: 1.3.0.qualifier
+Bundle-Version: 1.3.100.qualifier
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
 Export-Package: org.eclipse.osgi.framework.log;version="1.0",
diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/util/SecureAction.java b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/util/SecureAction.java
index 7a25fb5..400218d 100644
--- a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/util/SecureAction.java
+++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/util/SecureAction.java
@@ -175,6 +175,29 @@
 	}
 
 	/**
+	 * Returns the canonical path of a file.  Same as calling
+	 * file.getCanonicalPath().
+	 * @param file a file object
+	 * @return the canonical path of a file.
+	 * @throws IOException on error
+	 */
+	public String getCanonicalPath(final File file) throws IOException {
+		if (System.getSecurityManager() == null)
+			return file.getCanonicalPath();
+		try {
+			return (String) AccessController.doPrivileged(new PrivilegedExceptionAction() {
+				public Object run() throws IOException {
+					return file.getCanonicalPath();
+				}
+			}, controlContext);
+		} catch (PrivilegedActionException e) {
+			if (e.getException() instanceof IOException)
+				throw (IOException) e.getException();
+			throw (RuntimeException) e.getException();
+		}
+	}
+
+	/**
 	 * Returns true if a file exists, otherwise false is returned.  Same as calling
 	 * file.exists().
 	 * @param file a file object