All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.osgi.storage.StorageUtil Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/*******************************************************************************
 * 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
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * 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.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.Set;
import java.util.stream.Stream;
import org.eclipse.osgi.framework.internal.reliablefile.ReliableFile;
import org.eclipse.osgi.internal.debug.Debug;
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 {

	/**
	 * 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 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 walk = Files.walk(source)) {
				for (Path s : (Iterable) walk::iterator) {
					Path t = target.resolve(source.relativize(s));
					Files.copy(s, t, StandardCopyOption.REPLACE_EXISTING);
				}
			}
		}
	}

	/**
	 * Read a file from an InputStream and write it to the file system.
	 *
	 * @param in InputStream from which to read. This stream will be closed by this method.
	 * @param file output file to create.
	 * @exception IOException
	 */
	public static void readFile(InputStream in, File file) throws IOException {
		try (InputStream stream = in) {
			Files.copy(in, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
		}
	}

	/**
	 * This function performs the equivalent of "rm -r" on a file or directory.
	 *
	 * @param   file file or directory to delete
	 * @return false is the specified files still exists, true otherwise.
	 */
	public static boolean rm(File file, boolean DEBUG) {
		Path path = file.toPath();
		if (!Files.exists(path)) {
			return true;
		}
		try {
			Files.walkFileTree(path, new SimpleFileVisitor() {
				@Override
				public FileVisitResult visitFile(Path f, BasicFileAttributes attrs) {
					return delete(f, DEBUG);
				}

				@Override
				public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
					return delete(dir, DEBUG);
				}

				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;
		}
	}

	/**
	 * Register a service object.
	 * @param name the service class name
	 * @param service the service object
	 * @param context the registering bundle context
	 * @return the service registration object
	 */
	public static ServiceRegistration register(String name, Object service, BundleContext context) {
		Dictionary 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.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"
			fileTest = ReliableFile.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
			return false;
		} finally {
			if (fileTest != null)
				fileTest.delete();
		}
		return true;
	}

	public static URL encodeFileURL(File file) throws MalformedURLException {
		return file.toURI().toURL();
	}

	public static byte[] getBytes(InputStream in, int length, int BUF_SIZE) throws IOException {
		byte[] classbytes;
		int bytesread = 0;
		int readcount;
		try {
			if (length > 0) {
				classbytes = new byte[length];
				for (; bytesread < length; bytesread += readcount) {
					readcount = in.read(classbytes, bytesread, length - bytesread);
					if (readcount <= 0) /* if we didn't read anything */
						break; /* leave the loop */
				}
			} else /* does not know its own length! */ {
				length = BUF_SIZE;
				classbytes = new byte[length];
				readloop: while (true) {
					for (; bytesread < length; bytesread += readcount) {
						readcount = in.read(classbytes, bytesread, length - bytesread);
						if (readcount <= 0) /* if we didn't read anything */
							break readloop; /* leave the loop */
					}
					byte[] oldbytes = classbytes;
					length += BUF_SIZE;
					classbytes = new byte[length];
					System.arraycopy(oldbytes, 0, classbytes, 0, bytesread);
				}
			}
			if (classbytes.length > bytesread) {
				byte[] oldbytes = classbytes;
				classbytes = new byte[bytesread];
				System.arraycopy(oldbytes, 0, classbytes, 0, bytesread);
			}
		} finally {
			try {
				in.close();
			} catch (IOException ee) {
				// nothing to do here
			}
		}
		return classbytes;
	}

	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("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$
		}
	}

	private static final boolean IS_WINDOWS = File.separatorChar == '\\';

	// reserved names according to
	// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
	private static final Set 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$

	/** 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());
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy