Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/StorageUtil.java')
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/StorageUtil.java247
1 files changed, 104 insertions, 143 deletions
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/StorageUtil.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/StorageUtil.java
index 033c5b427..2c9eddf8b 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/StorageUtil.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/StorageUtil.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2016 IBM Corporation and others.
+ * Copyright (c) 2005, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,46 +10,55 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Hannes Wellmann - Bug 577432 - Speed up and improve file processing in Storage
*******************************************************************************/
package org.eclipse.osgi.storage;
-import java.io.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Arrays;
import java.util.Dictionary;
+import java.util.HashSet;
import java.util.Hashtable;
-import java.util.concurrent.TimeUnit;
+import java.util.Set;
+import java.util.stream.Stream;
import org.eclipse.osgi.internal.debug.Debug;
-import org.osgi.framework.*;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
/**
* A utility class with some generally useful static methods for adaptor hook implementations
*/
public class StorageUtil {
- /** The NULL tag used in bundle storage */
- public static final byte NULL = 0;
- /** The OBJECT tag used in bundle storage */
- public static final byte OBJECT = 1;
/**
- * Does a recursive copy of one directory to another.
- * @param inDir input directory to copy.
- * @param outDir output directory to copy to.
+ * Copies the content of the given path (file or directory) to the specified
+ * target. If the source is a directory all contained elements are copied
+ * recursively.
+ * @param inFile input directory to copy.
+ * @param outFile output directory to copy to.
* @throws IOException if any error occurs during the copy.
*/
- public static void copyDir(File inDir, File outDir) throws IOException {
- String[] files = inDir.list();
- if (files != null && files.length > 0) {
- outDir.mkdir();
- for (int i = 0; i < files.length; i++) {
- File inFile = new File(inDir, files[i]);
- File outFile = new File(outDir, files[i]);
- if (inFile.isDirectory()) {
- copyDir(inFile, outFile);
- } else {
- InputStream in = new FileInputStream(inFile);
- readFile(in, outFile);
+ public static void copy(File inFile, File outFile) throws IOException {
+ Path source = inFile.toPath();
+ Path target = outFile.toPath();
+ if (Files.exists(source)) {
+ Files.createDirectories(target.getParent());
+ try (Stream<Path> walk = Files.walk(source)) {
+ for (Path s : (Iterable<Path>) walk::iterator) {
+ Path t = target.resolve(source.relativize(s));
+ Files.copy(s, t, StandardCopyOption.REPLACE_EXISTING);
}
}
}
@@ -63,32 +72,7 @@ public class StorageUtil {
* @exception IOException
*/
public static void readFile(InputStream in, File file) throws IOException {
- FileOutputStream fos = null;
- try {
- fos = new FileOutputStream(file);
-
- byte buffer[] = new byte[1024];
- int count;
- while ((count = in.read(buffer, 0, buffer.length)) > 0) {
- fos.write(buffer, 0, count);
- }
- } finally {
- if (in != null) {
- try {
- in.close();
- } catch (IOException ee) {
- // nothing to do here
- }
- }
-
- if (fos != null) {
- try {
- fos.close();
- } catch (IOException ee) {
- // nothing to do here
- }
- }
- }
+ Files.copy(in, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
/**
@@ -98,51 +82,39 @@ public class StorageUtil {
* @return false is the specified files still exists, true otherwise.
*/
public static boolean rm(File file, boolean DEBUG) {
- if (file.exists()) {
- if (file.isDirectory()) {
- String list[] = file.list();
- if (list != null) {
- int len = list.length;
- for (int i = 0; i < len; i++) {
- // we are doing a lot of garbage collecting here
- rm(new File(file, list[i]), DEBUG);
- }
- }
- }
- if (DEBUG) {
- if (file.isDirectory()) {
- Debug.println("rmdir " + file.getPath()); //$NON-NLS-1$
- } else {
- Debug.println("rm " + file.getPath()); //$NON-NLS-1$
+ Path path = file.toPath();
+ if (!Files.exists(path)) {
+ return true;
+ }
+ try {
+ Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
+ @Override
+ public FileVisitResult visitFile(Path f, BasicFileAttributes attrs) {
+ return delete(f, DEBUG);
}
- }
- boolean success = file.delete();
-
- if (DEBUG) {
- if (!success) {
- Debug.println(" rm failed!"); //$NON-NLS-1$
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
+ return delete(dir, DEBUG);
}
- }
- return (success);
- }
- return (true);
- }
-
- public static String readString(DataInputStream in, boolean intern) throws IOException {
- byte type = in.readByte();
- if (type == NULL)
- return null;
- return intern ? in.readUTF().intern() : in.readUTF();
- }
-
- public static void writeStringOrNull(DataOutputStream out, String string) throws IOException {
- if (string == null)
- out.writeByte(NULL);
- else {
- out.writeByte(OBJECT);
- out.writeUTF(string);
+ private FileVisitResult delete(Path pathToDelete, boolean debug) {
+ try {
+ if (debug) {
+ Debug.println("rm " + pathToDelete); //$NON-NLS-1$
+ }
+ Files.delete(pathToDelete);
+ } catch (IOException e) {
+ if (debug) {
+ Debug.println(" rm failed:" + e.getMessage()); //$NON-NLS-1$
+ }
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ return !Files.exists(path);
+ } catch (IOException e) {
+ return false;
}
}
@@ -154,28 +126,28 @@ public class StorageUtil {
* @return the service registration object
*/
public static ServiceRegistration<?> register(String name, Object service, BundleContext context) {
- Dictionary<String, Object> properties = new Hashtable<>(7);
- Dictionary<String, String> headers = context.getBundle().getHeaders();
- properties.put(Constants.SERVICE_VENDOR, headers.get(Constants.BUNDLE_VENDOR));
+ Dictionary<String, Object> properties = new Hashtable<>();
properties.put(Constants.SERVICE_RANKING, Integer.valueOf(Integer.MAX_VALUE));
properties.put(Constants.SERVICE_PID, context.getBundle().getBundleId() + "." + service.getClass().getName()); //$NON-NLS-1$
return context.registerService(name, service, properties);
}
public static boolean canWrite(File installDir) {
- if (installDir.canWrite() == false)
- return false;
-
if (!installDir.isDirectory())
return false;
+ if (Files.isWritable(installDir.toPath()))
+ return true;
+
File fileTest = null;
try {
// we use the .dll suffix to properly test on Vista virtual directories
- // on Vista you are not allowed to write executable files on virtual directories like "Program Files"
+ // on Vista you are not allowed to write executable files on virtual directories
+ // like "Program Files"
fileTest = File.createTempFile("writableArea", ".dll", installDir); //$NON-NLS-1$ //$NON-NLS-2$
} catch (IOException e) {
- //If an exception occured while trying to create the file, it means that it is not writtable
+ // If an exception occured while trying to create the file, it means that it is
+ // not writtable
return false;
} finally {
if (fileTest != null)
@@ -230,58 +202,47 @@ public class StorageUtil {
return classbytes;
}
- /**
- * To remain Java 6 compatible work around the unreliable renameTo() via
- * retries: http://bugs.java.com/view_bug.do?bug_id=6213298
- *
- * @param from
- * @param to
- */
- public static boolean move(File from, File to, boolean DEBUG) {
- // Try several attempts with incremental sleep
- final int maxTries = 10;
- final int sleepStep = 200;
- for (int tryCount = 0, sleep = sleepStep;; sleep += sleepStep, tryCount++) {
- if (from.renameTo(to)) {
- return true;
- }
-
+ public static void move(File from, File to, boolean DEBUG) throws IOException {
+ try {
+ Files.move(from.toPath(), to.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
+ } catch (IOException e) {
if (DEBUG) {
- Debug.println("move: failed to rename " + from + " to " + to + " (" + (maxTries - tryCount) + " attempts remaining)"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
- }
-
- if (tryCount >= maxTries) {
- break;
- }
-
- try {
- TimeUnit.MILLISECONDS.sleep(sleep);
- } catch (InterruptedException e) {
- // Ignore
+ Debug.println("Failed to move atomically: " + from + " to " + to); //$NON-NLS-1$ //$NON-NLS-2$
}
+ // remove in case it failed because the target to non-empty directory or
+ // the target type does not match the from
+ rm(to, DEBUG);
+ // also, try without atomic operation
+ Files.move(from.toPath(), to.toPath(), StandardCopyOption.REPLACE_EXISTING);
+ }
+ if (DEBUG) {
+ Debug.println("Successfully moved file: " + from + " to " + to); //$NON-NLS-1$ //$NON-NLS-2$
}
+ }
- // Try a copy
- try {
- if (from.isDirectory()) {
- copyDir(from, to);
- } else {
- readFile(new FileInputStream(from), to);
- }
+ private static final boolean IS_WINDOWS = File.separatorChar == '\\';
- if (!rm(from, DEBUG)) {
- Debug.println("move: failed to delete " + from + " after copy to " + to + ". Scheduling for delete on JVM exit."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- from.deleteOnExit();
- }
- return true;
- } catch (IOException e) {
- if (DEBUG) {
- Debug.println("move: failed to copy " + from + " to " + to); //$NON-NLS-1$ //$NON-NLS-2$
- Debug.printStackTrace(e);
- }
+ // reserved names according to
+ // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
+ private static final Set<String> RESERVED_NAMES = new HashSet<>(Arrays.asList("aux", "com1", "com2", "com3", "com4", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "com5", "com6", "com7", "com8", "com9", "con", "lpt1", "lpt2", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "nul", "prn")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$
- // Give up
+ /** Tests whether the filename can escape path into special device **/
+ public static boolean isReservedFileName(File file) {
+ // Directory names are not checked here because illegal directory names will be
+ // handled by OS.
+ if (!IS_WINDOWS) { // only windows has special file names which can escape any path
return false;
}
+ String fileName = file.getName();
+ // Illegal characters are not checked here because they are check by both JDK
+ // and OS. This is only a check against technical allowed but unwanted device
+ // names.
+ int dot = fileName.indexOf('.');
+ // on windows, filename suffixes are not relevant to name validity
+ String basename = dot == -1 ? fileName : fileName.substring(0, dot);
+ return RESERVED_NAMES.contains(basename.toLowerCase());
}
+
}

Back to the top