support  uninstalling features
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/Feature.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/Feature.java
index dd0f713..f09aa36 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/core/Feature.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/Feature.java
@@ -382,6 +382,7 @@
 					pluginConsumer.store(references[j], subMonitor);

 				}

 

+				InstallRegistry.register("plugin_"+pluginsToInstall[i].getVersionedIdentifier());

 				if (monitor.isCanceled())

 						abort();

 			}

@@ -402,6 +403,7 @@
 					setMonitorTaskName(subMonitor, msg + " " + references[i].getIdentifier());

 					consumer.store(references[i], subMonitor);

 				}

+				InstallRegistry.register("feature_"+getVersionedIdentifier());

 			} else {

 				monitor.worked(1);

 			}

diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InstallRegistry.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InstallRegistry.java
new file mode 100644
index 0000000..21b97de
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InstallRegistry.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.internal.core;
+
+import java.io.*;
+import java.util.*;
+
+import org.eclipse.core.boot.*;
+
+/**
+ * Keeps track of all the features and plugins installed by Update mgr.
+ */
+public class InstallRegistry extends Properties {
+	private File file = null;
+	private final static String REGISTRY = "registry";
+	private static InstallRegistry instance;
+	/**
+	 * Creates empty Properties.
+	 * @param name name of the table;
+	 */
+	private InstallRegistry() {
+		super();
+		String configFile =
+			BootLoader
+				.getCurrentPlatformConfiguration()
+				.getConfigurationLocation()
+				.getFile();
+		file = new File(configFile);
+		file = file.getParentFile();
+		file = new File(file, REGISTRY);
+		restore();
+	}
+
+	/**
+	 * Singleton
+	 */
+	public static InstallRegistry getInstance() {
+		if (instance == null)
+			instance = new InstallRegistry();
+		return instance;
+	}
+
+	/**
+	 * Restores contents of the Properties from a file.
+	 * @return true if persistant data was read in
+	 */
+	public boolean restore() {
+		InputStream in = null;
+		boolean loaded = false;
+		clear();
+		// Test if we have a contribution file to start with
+		// If this is a clean start, then we will not have a 
+		// contribution file. return false.
+		if (!file.exists())
+			return loaded;
+		try {
+			in = new FileInputStream(file);
+			super.load(in);
+			loaded = true;
+		} catch (IOException e) {
+			UpdateCore.log(e);
+		} finally {
+			if (in != null)
+				try {
+					in.close();
+				} catch (IOException e) {
+				}
+		}
+		return loaded;
+	}
+	/**
+	 * Saves contents of the table to a file.
+	 * @return true if operation was successful
+	 */
+	public synchronized boolean save() {
+		OutputStream out = null;
+		boolean ret = false;
+		try {
+			out = new FileOutputStream(file);
+			super.store(out, "This is a generated file; do not edit.");
+			ret = true;
+		} catch (IOException e) {
+			UpdateCore.log(e);
+		} finally {
+			try {
+				if (out != null) {
+					out.close();
+				}
+			} catch (IOException e) {
+			}
+		}
+		return ret;
+	}
+
+	/**
+	 * Registers an installed feature or plugin so it can be uninstalled later.
+	 * @param name: For feature this is feature_<id>_<version> and for plugins
+	 * it is plugin_<id>_<version>. Eg: feature_org.eclipse.platform_3.0.0
+	 */
+	public static synchronized void register(String name) {
+		if (InstallRegistry.getInstance().get(name) == null) {
+			InstallRegistry.getInstance().put(name, name);
+			// we save after each registration
+			InstallRegistry.getInstance().save();
+		}
+	}
+
+	/**
+	 * Removes specified name from registry
+	 *
+	 */
+	public static synchronized void unregister(String name) {
+		InstallRegistry.getInstance().remove(name);
+	}
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFile.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFile.java
index f2354e9..2f1e0f8 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFile.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFile.java
@@ -15,6 +15,7 @@
 import org.eclipse.core.runtime.*;

 import org.eclipse.update.core.*;

 import org.eclipse.update.core.model.*;

+import org.eclipse.update.internal.operations.*;

 

 /**

  * Site on the File System

@@ -117,7 +118,7 @@
 			UpdateCore.warn("Feature to remove is null");

 			return;

 		}

-

+		

 		ErrorRecoveryLog recoveryLog = ErrorRecoveryLog.getLog();

 

 		// make sure we have an InstallMonitor		

@@ -167,17 +168,22 @@
 				}

 			}

 

-			// remove the feature content

-			ContentReference[] references = feature.getFeatureContentProvider().getFeatureEntryArchiveReferences(monitor);

-			for (int i = 0; i < references.length; i++) {

-				try {

-					UpdateManagerUtils.removeFromFileSystem(references[i].asFile());

-					if (monitor != null)

-						monitor.worked(1);

-				} catch (IOException e) {

-					throw Utilities.newCoreException(Policy.bind("SiteFile.CannotRemoveFeature", feature.getVersionedIdentifier().getIdentifier(), getURL().toExternalForm()), e);

-					//$NON-NLS-1$

+			if (InstallRegistry.getInstance().get("feature_"+feature.getVersionedIdentifier()) == null) {

+				UpdateCore.log("Feature " + feature.getVersionedIdentifier() + " was not removed", null);

+			} else {

+				// remove the feature content

+				ContentReference[] references = feature.getFeatureContentProvider().getFeatureEntryArchiveReferences(monitor);

+				for (int i = 0; i < references.length; i++) {

+					try {

+						UpdateManagerUtils.removeFromFileSystem(references[i].asFile());

+						if (monitor != null)

+							monitor.worked(1);

+					} catch (IOException e) {

+						throw Utilities.newCoreException(Policy.bind("SiteFile.CannotRemoveFeature", feature.getVersionedIdentifier().getIdentifier(), getURL().toExternalForm()), e);

+						//$NON-NLS-1$

+					}

 				}

+				InstallRegistry.unregister("feature_"+feature.getVersionedIdentifier());

 			}

 

 			//finds the contentReferences for an IPluginEntry

@@ -359,6 +365,11 @@
 

 		if (pluginEntry == null)

 			return;

+			

+		if (InstallRegistry.getInstance().get("plugin_"+pluginEntry.getVersionedIdentifier()) == null) {

+			UpdateCore.log("Plugin " + pluginEntry.getVersionedIdentifier() + " was not removed", null);

+			return; 

+		}

 

 		ContentReference[] references = feature.getFeatureContentProvider().getPluginEntryArchiveReferences(pluginEntry, monitor);

 		for (int i = 0; i < references.length; i++) {

@@ -371,6 +382,7 @@
 				//$NON-NLS-1$

 			}

 		}

+		InstallRegistry.unregister("plugin_"+pluginEntry.getVersionedIdentifier());

 	}

 

 	/*