Bug 364507 - [prefs] Preferences lost on disk full
diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/EclipsePreferences.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/EclipsePreferences.java
index ae832fc..ee30ae8 100644
--- a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/EclipsePreferences.java
+++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/EclipsePreferences.java
@@ -294,7 +294,7 @@
OutputStream output = null;
try {
- output = new BufferedOutputStream(new FileOutputStream(new File(location.toOSString())));
+ output = new SafeFileOutputStream(new File(location.toOSString()));
output.write(removeTimestampFromTable(properties).getBytes("UTF-8")); //$NON-NLS-1$
output.flush();
} catch (IOException e) {
@@ -687,7 +687,7 @@
InputStream input = null;
Properties result = new Properties();
try {
- input = new BufferedInputStream(new FileInputStream(location.toFile()));
+ input = new SafeFileInputStream(location.toFile());
result.load(input);
} catch (FileNotFoundException e) {
// file doesn't exist but that's ok.
diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/SafeFileInputStream.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/SafeFileInputStream.java
new file mode 100644
index 0000000..e7a3823
--- /dev/null
+++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/SafeFileInputStream.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.core.internal.preferences;
+
+import java.io.*;
+
+/**
+ * Given a target and a temporary locations, it tries to read the contents
+ * from the target. If a file does not exist at the target location, it tries
+ * to read the contents from the temporary location.
+ * This class handles buffering of output stream contents.
+ *
+ * Copied from org.eclipse.core.internal.localstore.SafeFileOutputStream
+ *
+ * @see SafeFileOutputStream
+ */
+public class SafeFileInputStream extends FilterInputStream {
+ protected static final String EXTENSION = ".bak"; //$NON-NLS-1$
+
+ public SafeFileInputStream(File file) throws IOException {
+ this(file.getAbsolutePath(), null);
+ }
+
+ /**
+ * If targetPath is null, the file will be created in the default-temporary directory.
+ */
+ public SafeFileInputStream(String targetPath, String tempPath) throws IOException {
+ super(getInputStream(targetPath, tempPath));
+ }
+
+ private static InputStream getInputStream(String targetPath, String tempPath) throws IOException {
+ File target = new File(targetPath);
+ if (!target.exists()) {
+ if (tempPath == null)
+ tempPath = target.getAbsolutePath() + EXTENSION;
+ target = new File(tempPath);
+ }
+ return new BufferedInputStream(new FileInputStream(target));
+ }
+}
diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/SafeFileOutputStream.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/SafeFileOutputStream.java
new file mode 100644
index 0000000..f4a8713
--- /dev/null
+++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/SafeFileOutputStream.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * James Blackburn (Broadcom Corp.) - ongoing development
+ *******************************************************************************/
+package org.eclipse.core.internal.preferences;
+
+import java.io.*;
+
+/**
+ * This class should be used when there's a file already in the
+ * destination and we don't want to lose its contents if a
+ * failure writing this stream happens.
+ * Basically, the new contents are written to a temporary location.
+ * If everything goes OK, it is moved to the right place.
+ * This class handles buffering of output stream contents.
+ *
+ * Copied from org.eclipse.core.internal.localstore.SafeFileOutputStream
+ */
+public class SafeFileOutputStream extends OutputStream {
+ protected File temp;
+ protected File target;
+ protected OutputStream output;
+ protected boolean failed;
+ protected static final String EXTENSION = ".bak"; //$NON-NLS-1$
+
+ /**
+ * Creates an output stream on a file at the given location
+ * @param file The file to be written to
+ */
+ public SafeFileOutputStream(File file) throws IOException {
+ failed = false;
+ target = file;
+ temp = new File(target.getAbsolutePath() + EXTENSION);
+ if (!target.exists()) {
+ if (!temp.exists()) {
+ output = new BufferedOutputStream(new FileOutputStream(target));
+ return;
+ }
+ // If we do not have a file at target location, but we do have at temp location,
+ // it probably means something wrong happened the last time we tried to write it.
+ // So, try to recover the backup file. And, if successful, write the new one.
+ copy(temp, target);
+ }
+ output = new BufferedOutputStream(new FileOutputStream(temp));
+ }
+
+ public void close() throws IOException {
+ try {
+ output.close();
+ } catch (IOException e) {
+ failed = true;
+ throw e; // rethrow
+ }
+ if (failed)
+ temp.delete();
+ else
+ commit();
+ }
+
+ protected void commit() throws IOException {
+ if (!temp.exists())
+ return;
+ target.delete();
+ copy(temp, target);
+ temp.delete();
+ }
+
+ protected void copy(File sourceFile, File destinationFile) throws IOException {
+ if (!sourceFile.exists())
+ return;
+ if (sourceFile.renameTo(destinationFile))
+ return;
+ InputStream source = null;
+ OutputStream destination = null;
+ try {
+ source = new BufferedInputStream(new FileInputStream(sourceFile));
+ destination = new BufferedOutputStream(new FileOutputStream(destinationFile));
+ transferStreams(source, destination);
+ } finally {
+ try {
+ if (source != null)
+ source.close();
+ } finally {
+ //ignore secondary exception
+ }
+ try {
+ if (destination != null)
+ destination.close();
+ } finally {
+ //ignore secondary exception
+ }
+ }
+ }
+
+ public void flush() throws IOException {
+ try {
+ output.flush();
+ } catch (IOException e) {
+ failed = true;
+ throw e; // rethrow
+ }
+ }
+
+ public String getTempFilePath() {
+ return temp.getAbsolutePath();
+ }
+
+ protected void transferStreams(InputStream source, OutputStream destination) throws IOException {
+ byte[] buffer = new byte[8192];
+ while (true) {
+ int bytesRead = source.read(buffer);
+ if (bytesRead == -1)
+ break;
+ destination.write(buffer, 0, bytesRead);
+ }
+ }
+
+ public void write(int b) throws IOException {
+ try {
+ output.write(b);
+ } catch (IOException e) {
+ failed = true;
+ throw e; // rethrow
+ }
+ }
+}