/*******************************************************************************
* Copyright (c) 2005, 2008 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
* Martin Oberhuber (Wind River) - [44107] Add symbolic links to ResourceAttributes API
*******************************************************************************/
package org.eclipse.core.internal.utils;
import java.io.*;
import java.net.URI;
import org.eclipse.core.filesystem.*;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.internal.resources.ResourceException;
import org.eclipse.core.internal.resources.Workspace;
import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.resources.ResourceAttributes;
import org.eclipse.core.runtime.*;
import org.eclipse.osgi.util.NLS;
/**
* Static utility methods for manipulating Files and URIs.
*/
public class FileUtil {
/**
* Singleton buffer created to prevent buffer creations in the transferStreams method. Used as
* an optimization, based on the assumption that multiple writes won't happen in a given
* instance of FileStore.
*/
private static final byte[] buffer= new byte[8192];
/**
* Converts a ResourceAttributes object into an IFileInfo object.
*
* @param attributes The resource attributes
* @return The file info
*/
public static IFileInfo attributesToFileInfo(ResourceAttributes attributes) {
IFileInfo fileInfo= EFS.createFileInfo();
fileInfo.setAttribute(EFS.ATTRIBUTE_READ_ONLY, attributes.isReadOnly());
fileInfo.setAttribute(EFS.ATTRIBUTE_EXECUTABLE, attributes.isExecutable());
fileInfo.setAttribute(EFS.ATTRIBUTE_ARCHIVE, attributes.isArchive());
fileInfo.setAttribute(EFS.ATTRIBUTE_HIDDEN, attributes.isHidden());
return fileInfo;
}
/**
* Converts an IPath into its canonical form for the local file system.
*/
public static IPath canonicalPath(IPath path) {
if (path == null)
return null;
try {
final String pathString= path.toOSString();
final String canonicalPath= new java.io.File(pathString).getCanonicalPath();
//only create a new path if necessary
if (canonicalPath.equals(pathString))
return path;
return new Path(canonicalPath);
} catch (IOException e) {
return path;
}
}
/**
* Converts a URI into its canonical form.
*/
public static URI canonicalURI(URI uri) {
if (uri == null)
return null;
if (EFS.SCHEME_FILE.equals(uri.getScheme())) {
//only create a new URI if it is different
final IPath inputPath= URIUtil.toPath(uri);
final IPath canonicalPath= canonicalPath(inputPath);
if (inputPath == canonicalPath)
return uri;
return URIUtil.toURI(canonicalPath);
}
return uri;
}
/**
* Returns true if the given file system locations overlap. If "bothDirections" is true, this
* means they are the same, or one is a proper prefix of the other. If "bothDirections" is
* false, this method only returns true if the locations are the same, or the first location is
* a prefix of the second. Returns false if the locations do not overlap Does the right thing
* with respect to case insensitive platforms.
*/
private static boolean computeOverlap(IPath location1, IPath location2, boolean bothDirections) {
IPath one= location1;
IPath two= location2;
// If we are on a case-insensitive file system then convert to all lower case.
if (!Workspace.caseSensitive) {
one= new Path(location1.toOSString().toLowerCase());
two= new Path(location2.toOSString().toLowerCase());
}
return one.isPrefixOf(two) || (bothDirections && two.isPrefixOf(one));
}
/**
* Returns true if the given file system locations overlap. If "bothDirections" is true, this
* means they are the same, or one is a proper prefix of the other. If "bothDirections" is
* false, this method only returns true if the locations are the same, or the first location is
* a prefix of the second. Returns false if the locations do not overlap
*/
private static boolean computeOverlap(URI location1, URI location2, boolean bothDirections) {
if (location1.equals(location2))
return true;
String scheme1= location1.getScheme();
String scheme2= location2.getScheme();
if (scheme1 == null ? scheme2 != null : !scheme1.equals(scheme2))
return false;
if (EFS.SCHEME_FILE.equals(scheme1) && EFS.SCHEME_FILE.equals(scheme2))
return computeOverlap(URIUtil.toPath(location1), URIUtil.toPath(location2), bothDirections);
IFileSystem system= null;
try {
system= EFS.getFileSystem(scheme1);
} catch (CoreException e) {
//handled below
}
if (system == null) {
//we are stuck with string comparison
String string1= location1.toString();
String string2= location2.toString();
return string1.startsWith(string2) || (bothDirections && string2.startsWith(string1));
}
IFileStore store1= system.getStore(location1);
IFileStore store2= system.getStore(location2);
return store1.equals(store2) || store1.isParentOf(store2) || (bothDirections && store2.isParentOf(store1));
}
/**
* Converts an IFileInfo object into a ResourceAttributes object.
*
* @param fileInfo The file info
* @return The resource attributes
*/
public static ResourceAttributes fileInfoToAttributes(IFileInfo fileInfo) {
ResourceAttributes attributes= new ResourceAttributes();
attributes.setReadOnly(fileInfo.getAttribute(EFS.ATTRIBUTE_READ_ONLY));
attributes.setArchive(fileInfo.getAttribute(EFS.ATTRIBUTE_ARCHIVE));
attributes.setExecutable(fileInfo.getAttribute(EFS.ATTRIBUTE_EXECUTABLE));
attributes.setHidden(fileInfo.getAttribute(EFS.ATTRIBUTE_HIDDEN));
attributes.setSymbolicLink(fileInfo.getAttribute(EFS.ATTRIBUTE_SYMLINK));
return attributes;
}
/**
* Returns true if the given file system locations overlap, and false otherwise. Overlap means
* the locations are the same, or one is a proper prefix of the other.
*/
public static boolean isOverlapping(URI location1, URI location2) {
return computeOverlap(location1, location2, true);
}
/**
* Returns true if location1 is the same as, or a proper prefix of, location2. Returns false
* otherwise.
*/
public static boolean isPrefixOf(IPath location1, IPath location2) {
return computeOverlap(location1, location2, false);
}
/**
* Returns true if location1 is the same as, or a proper prefix of, location2. Returns false
* otherwise.
*/
public static boolean isPrefixOf(URI location1, URI location2) {
return computeOverlap(location1, location2, false);
}
/**
* Closes a stream and ignores any resulting exception. This is useful when doing stream cleanup
* in a finally block where secondary exceptions are not worth logging.
*/
public static void safeClose(InputStream in) {
try {
if (in != null)
in.close();
} catch (IOException e) {
//ignore
}
}
/**
* Closes a stream and ignores any resulting exception. This is useful when doing stream cleanup
* in a finally block where secondary exceptions are not worth logging.
*/
public static void safeClose(OutputStream out) {
try {
if (out != null)
out.close();
} catch (IOException e) {
//ignore
}
}
/**
* Converts a URI to an IPath. Returns null if the URI cannot be represented as an IPath.
* <p>
* Note this method differs from URIUtil in its handling of relative URIs as being relative to
* path variables.
*/
public static IPath toPath(URI uri) {
if (uri == null)
return null;
final String scheme= uri.getScheme();
// null scheme represents path variable
if (scheme == null || EFS.SCHEME_FILE.equals(scheme))
return new Path(uri.getSchemeSpecificPart());
return null;
}
public static final void transferStreams(InputStream source, OutputStream destination, String path, IProgressMonitor monitor) throws CoreException {
monitor= Policy.monitorFor(monitor);
try {
/*
* Note: although synchronizing on the buffer is thread-safe,
* it may result in slower performance in the future if we want
* to allow concurrent writes.
*/
synchronized (buffer) {
while (true) {
int bytesRead= -1;
try {
bytesRead= source.read(buffer);
} catch (IOException e) {
String msg= NLS.bind(Messages.localstore_failedReadDuringWrite, path);
throw new ResourceException(IResourceStatus.FAILED_READ_LOCAL, new Path(path), msg, e);
}
if (bytesRead == -1)
break;
try {
destination.write(buffer, 0, bytesRead);
} catch (IOException e) {
String msg= NLS.bind(Messages.localstore_couldNotWrite, path);
throw new ResourceException(IResourceStatus.FAILED_WRITE_LOCAL, new Path(path), msg, e);
}
monitor.worked(1);
}
}
} finally {
safeClose(source);
safeClose(destination);
}
}
/**
* Not intended for instantiation.
*/
private FileUtil() {
super();
}
}