diff options
Diffstat (limited to 'bundles/org.eclipse.equinox.p2.touchpoint.natives/src/org/eclipse/equinox/internal/prov/touchpoint/natives/BackupFiles.java')
-rw-r--r-- | bundles/org.eclipse.equinox.p2.touchpoint.natives/src/org/eclipse/equinox/internal/prov/touchpoint/natives/BackupFiles.java | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.p2.touchpoint.natives/src/org/eclipse/equinox/internal/prov/touchpoint/natives/BackupFiles.java b/bundles/org.eclipse.equinox.p2.touchpoint.natives/src/org/eclipse/equinox/internal/prov/touchpoint/natives/BackupFiles.java new file mode 100644 index 000000000..7c47ebb7b --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.touchpoint.natives/src/org/eclipse/equinox/internal/prov/touchpoint/natives/BackupFiles.java @@ -0,0 +1,319 @@ +/******************************************************************************* + * Copyright (c) 2007 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.equinox.internal.prov.touchpoint.natives; + +import java.io.*; +import java.net.URL; +import java.util.*; +import java.util.zip.*; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.equinox.prov.core.helpers.FileUtils; +import org.eclipse.osgi.util.NLS; + +public class BackupFiles { + + private static final String ZIP_SUFFIX = ".zip"; //$NON-NLS-1$ + private static final String PROPERTIES_SUFFIX = ".properties"; //$NON-NLS-1$ + + private final File backupDir; + private boolean doBackup; + + /** + * Save or restore backups of files in backupDir + */ + public BackupFiles(File backupDir) { + this.doBackup = true; + this.backupDir = backupDir; + this.backupDir.mkdirs(); + } + + // /** + // * If doBackup is set to false, files are deleted on uninstall, instead of restored. + // */ + // public void setDoBackup(boolean doBackup) { + // this.doBackup = doBackup; + // } + + /** + * Restore all backups made in this dir. + */ + public void restore(IProgressMonitor monitor) throws IOException { + // find backup properties files, do in reverse order + List propsFiles = new LinkedList(); + for (int i = 0;; i += 1) { + File propsFile = getBackupProperties(i); + if (!propsFile.exists()) { + break; + } + propsFiles.add(0, propsFile); + } + IProgressMonitor[] pm = Util.splitProgressMonitor(monitor, propsFiles.size()); + int j = 0; + for (Iterator i = propsFiles.iterator(); i.hasNext();) { + File propsFile = (File) i.next(); + restoreFilesFromBackup(propsFile, pm[j++]); + } + if (!this.backupDir.delete()) { + //not empty? log a warning? + } else { + // delete the parent if empty + this.backupDir.getParentFile().delete(); + } + monitor.done(); + } + + /** + * Find files under outputDir that will be overwritten in unzipURL + * and save under backupDir, and delete. + * Include properties file to indicate files to delete or restore on rolled back. + * The progress monitor is used only to display sub-tasks; we don't update it otherwise. + */ + public void backupFilesInZip(String identifier, URL zipURL, File outputDir, IProgressMonitor monitor) throws IOException { + BackupProperties backupProps = new BackupProperties(identifier, outputDir); + ZipOutputStream zos = null; + String prevDir = null; + try { + ZipInputStream in = new ZipInputStream(zipURL.openStream()); + ZipEntry ze; + while ((ze = in.getNextEntry()) != null) { + String name = ze.getName(); + int i = name.lastIndexOf('/'); + if (i != -1) { + String dir = name.substring(0, i); + if (this.doBackup && !dir.equals(prevDir)) { + monitor.subTask(name.substring(0, i)); + prevDir = dir; + } + } + if (!ze.isDirectory()) { + File origFile = new File(outputDir, name); + if (this.doBackup && origFile.exists()) { + if (zos == null) { + File zipFile = backupProps.getArchive(); + zos = new ZipOutputStream(new FileOutputStream(zipFile)); + } + ZipEntry zipEntry = new ZipEntry(name); + zipEntry.setTime(origFile.lastModified()); + zos.putNextEntry(zipEntry); + FileUtils.copyStream(new FileInputStream(origFile), true, zos, false); + zos.closeEntry(); + } else { + backupProps.addFileToDelete(name); + } + origFile.delete(); + } + in.closeEntry(); + } + in.close(); + } finally { + backupProps.store(); + if (zos != null) { + zos.close(); + } + } + } + + private void restoreFilesFromBackup(File propsFile, IProgressMonitor monitor) throws IOException { + BackupProperties backupProps = new BackupProperties(propsFile); + monitor.beginTask(NLS.bind(Messages.restoring, propsFile.toString()), 3); + monitor.subTask(""); + for (Iterator i = backupProps.getFilesToDelete().iterator(); i.hasNext();) { + String name = (String) i.next(); + File full = new File(backupProps.getRootDir(), name); + full.delete(); + } + monitor.worked(1); + File zipFile = backupProps.getArchive(); + if (zipFile.exists()) { // only exists if files were saved + SubProgressMonitor sub = new SubProgressMonitor(monitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK); + FileUtils.unzipFile(zipFile, backupProps.getRootDir(), "", sub); + zipFile.delete(); + } else { + monitor.worked(1); + } + for (Iterator i = backupProps.getDirsToDelete().iterator(); i.hasNext();) { + String name = (String) i.next(); + File full = new File(backupProps.getRootDir(), name); + FileUtils.deleteEmptyDirs(full); + } + propsFile.delete(); + monitor.worked(1); + monitor.done(); + } + + // Backup files are just 0.properties, 1.properties, etc. + // Get the next unused one. + private File getBackupProperties() { + for (int i = 0;; i += 1) { + File result = getBackupProperties(i); + if (!result.exists()) + return result; + } + } + + private File getBackupProperties(int i) { + return new File(BackupFiles.this.backupDir, Integer.toString(i) + PROPERTIES_SUFFIX); + } + + private class BackupProperties extends Properties { + private static final long serialVersionUID = 2268313492348533029L; + private static final char FILE_KIND = 'f'; + private static final char DIR_KIND = 'd'; + private static final String ROOT_DIR = "rootDir"; //$NON-NLS-1$ + private static final String ARTIFACT_KEY = "artifactKey"; //$NON-NLS-1$ + // private static final String ARTIFACT_USER = "artifactUser"; //$NON-NLS-1$ + + private int n = 0; // number of properties + private File file; // file to store properties in + private List keys = new LinkedList(); // keys, in order they were added or read + private final File rootDir; // root of where files are going + private Set dirsToCreate = new TreeSet(); // set of dirs we will create + + // create properties based on file we are backing up to + public BackupProperties(String identifier, File rootDir) { + this.file = BackupFiles.this.getBackupProperties(); + this.rootDir = rootDir; + setProperty(ROOT_DIR, rootDir.getPath().replace('\\', '/')); + setProperty(ARTIFACT_KEY, (identifier != null ? identifier : rootDir.getAbsolutePath())); + // setProperty(ARTIFACT_USER, artifact.toUserString()); + // make sure rootDir is deleted if appropriate + addDir("./"); //$NON-NLS-1$ + } + + // create backup properties from a previously saved BackupProperties + public BackupProperties(File file) throws IOException { + this.file = file; + FileInputStream stream = new FileInputStream(file); + try { + load(stream); + } finally { + stream.close(); + } + this.rootDir = new File(getProperty(ROOT_DIR)); + } + + // public String getArtifactKey() { + // return getProperty(ARTIFACT_KEY); + // } + + // public String getArtifactUserString() { + // String result = getProperty(ARTIFACT_USER); + // if (result != null) { + // return result; + // } else { + // // return something if the key wasn't saved + // result = getArtifactKey(); + // result = result.replaceFirst(",native,", ","); //$NON-NLS-1$ //$NON-NLS-2$ + // return result.replace(',', ' ').trim(); + // } + // } + + public File getRootDir() { + return this.rootDir; + } + + // We are backing up files for this artifact. + // Create a backup zip based on the artifact key (as a hint). + public File getArchive() { + String path = this.file.getPath(); + if (path.endsWith(PROPERTIES_SUFFIX)) { + path = path.substring(0, path.length() - PROPERTIES_SUFFIX.length()); + } + return new File(path + ZIP_SUFFIX); + } + + public List getFilesToDelete() { + return getMatchingProperties(FILE_KIND); + } + + public List getDirsToDelete() { + return getMatchingProperties(DIR_KIND); + } + + private List getMatchingProperties(char c) { + List result = new LinkedList(); + for (Enumeration e = propertyNames(); e.hasMoreElements();) { + String key = (String) e.nextElement(); + if (key.equals(BackupProperties.ROOT_DIR)) { + continue; + } + if (key.charAt(0) == c) { + result.add(getProperty(key)); + } + } + return result; + } + + public void addFileToDelete(String name) { + add(FILE_KIND, name); + addDir(name); + } + + public void store() throws IOException { + // add the directories -- at end because we want them all in order + for (Iterator i = this.dirsToCreate.iterator(); i.hasNext();) { + String name = (String) i.next(); + add(DIR_KIND, name); + } + FileOutputStream stream = new FileOutputStream(this.file); + try { + store(stream, /*header*/null); + } finally { + stream.close(); + } + } + + public Object put(Object key, Object value) { + if (!(key instanceof String)) + throw new AssertionError("expected String: " + key); //$NON-NLS-1$ + if (!(value instanceof String)) + throw new AssertionError("expected String: " + value); //$NON-NLS-1$ + this.keys.add(key); + return super.put(key, value); + } + + // return keys in the order they were added + public synchronized Enumeration keys() { + final Iterator iterator = this.keys.iterator(); + return new Enumeration() { + public boolean hasMoreElements() { + return iterator.hasNext(); + } + + public Object nextElement() { + return iterator.next(); + } + }; + } + + private void add(char kind, String name) { + StringBuffer key = new StringBuffer(4); + key.append(kind).append(n++); + setProperty(key.toString(), name.replace('\\', '/')); + } + + // if we're going to create this dir, remember that so we delete it + private void addDir(String name) { + int slash = name.lastIndexOf('/'); + if (slash == -1) + return; // no dir + String dirName = name.substring(0, slash); + if (this.dirsToCreate.contains(dirName)) + return; // already have it + if (new File(this.rootDir, dirName).exists()) + return; // already exists + this.dirsToCreate.add(dirName); + } + + } + +} |