package org.eclipse.core.internal.resources;
import java.net.URI;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.internal.utils.FileUtil;
import org.eclipse.core.internal.utils.Messages;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.osgi.util.NLS;
public class LocationValidator {
private final Workspace workspace;
public LocationValidator(Workspace workspace) {
this.workspace = workspace;
}
private String toString(URI uri) {
try {
return EFS.getStore(uri).toString();
} catch (CoreException e) {
return uri.toString();
}
}
private IStatus validateAbsolute(URI location, boolean error) {
if (!location.isAbsolute()) {
String message;
String schemeSpecificPart = location.getSchemeSpecificPart();
if (schemeSpecificPart == null || schemeSpecificPart.isEmpty()) {
message = Messages.links_noPath;
} else {
IPath pathPart = new Path(schemeSpecificPart);
if (pathPart.segmentCount() > 0)
message = NLS.bind(Messages.pathvar_undefined, location.toString(), pathPart.segment(0));
else
message = Messages.links_noPath;
}
int code = error ? IResourceStatus.VARIABLE_NOT_DEFINED : IResourceStatus.VARIABLE_NOT_DEFINED_WARNING;
return new ResourceStatus(code, null, message);
}
return Status.OK_STATUS;
}
public IStatus validateLinkLocation(IResource resource, IPath unresolvedLocation) {
IPath location = resource.getPathVariableManager().resolvePath(unresolvedLocation);
if (location.isEmpty())
return new ResourceStatus(IResourceStatus.INVALID_VALUE, resource.getFullPath(), Messages.links_noPath);
if (!location.isAbsolute()) {
String message = NLS.bind(Messages.pathvar_undefined, location.toOSString(), location.segment(0));
return new ResourceStatus(IResourceStatus.VARIABLE_NOT_DEFINED_WARNING, resource.getFullPath(), message);
}
if (location.getDevice() == null)
location = new Path(location.toFile().getAbsolutePath());
return validateLinkLocationURI(resource, URIUtil.toURI(location));
}
public IStatus validateLinkLocationURI(IResource resource, URI unresolvedLocation) {
String schemeSpecificPart = unresolvedLocation.getSchemeSpecificPart();
if (schemeSpecificPart == null || schemeSpecificPart.isEmpty()) {
return new ResourceStatus(IResourceStatus.INVALID_VALUE, resource.getFullPath(), Messages.links_noPath);
}
String message;
if (ResourcesPlugin.getPlugin().getPluginPreferences().getBoolean(ResourcesPlugin.PREF_DISABLE_LINKING)) {
message = NLS.bind(Messages.links_workspaceVeto, resource.getName());
return new ResourceStatus(IResourceStatus.INVALID_VALUE, resource.getFullPath(), message);
}
int type = resource.getType();
if (type != IResource.FOLDER && type != IResource.FILE) {
message = NLS.bind(Messages.links_notFileFolder, resource.getName());
return new ResourceStatus(IResourceStatus.INVALID_VALUE, resource.getFullPath(), message);
}
IContainer parent = resource.getParent();
if (!parent.isAccessible()) {
message = NLS.bind(Messages.links_parentNotAccessible, resource.getFullPath());
return new ResourceStatus(IResourceStatus.INVALID_VALUE, resource.getFullPath(), message);
}
URI location = resource.getPathVariableManager().resolveURI(unresolvedLocation);
String[] natureIds = ((Project) resource.getProject()).internalGetDescription().getNatureIds();
IStatus result = workspace.getNatureManager().validateLinkCreation(natureIds);
if (!result.isOK())
return result;
if (resource.getType() == IResource.FILE)
result = workspace.getTeamHook().validateCreateLink((IFile) resource, IResource.NONE, location);
else
result = workspace.getTeamHook().validateCreateLink((IFolder) resource, IResource.NONE, location);
if (!result.isOK())
return result;
result = validateSegments(location);
if (!result.isOK())
return result;
result = validateAbsolute(location, false);
if (!result.isOK())
return result;
URI testLocation = workspace.getMetaArea().getLocation().toFile().toURI();
if (FileUtil.isOverlapping(location, testLocation)) {
message = NLS.bind(Messages.links_invalidLocation, toString(location));
return new ResourceStatus(IResourceStatus.INVALID_VALUE, resource.getFullPath(), message);
}
testLocation = resource.getProject().getLocationURI();
if (testLocation != null && FileUtil.isPrefixOf(location, testLocation)) {
message = NLS.bind(Messages.links_locationOverlapsProject, toString(location));
return new ResourceStatus(IResourceStatus.INVALID_VALUE, resource.getFullPath(), message);
}
for (IProject project : workspace.getRoot().getProjects(IContainer.INCLUDE_HIDDEN)) {
IProjectDescription desc = ((Project) project).internalGetDescription();
testLocation = desc.getLocationURI();
if (testLocation != null && FileUtil.isOverlapping(location, testLocation)) {
message = NLS.bind(Messages.links_overlappingResource, toString(location));
return new ResourceStatus(IResourceStatus.OVERLAPPING_LOCATION, resource.getFullPath(), message);
}
if (!project.isOpen())
continue;
IResource[] children = null;
try {
children = project.members();
} catch (CoreException e) {
}
if (children == null)
continue;
for (IResource child : children) {
if (child.isLinked()) {
testLocation = child.getLocationURI();
if (testLocation != null && FileUtil.isOverlapping(location, testLocation)) {
message = NLS.bind(Messages.links_overlappingResource, toString(location));
return new ResourceStatus(IResourceStatus.OVERLAPPING_LOCATION, resource.getFullPath(), message);
}
}
}
}
return Status.OK_STATUS;
}
public IStatus validateName(String segment, int type) {
String message;
if (segment == null) {
message = Messages.resources_nameNull;
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
if (segment.length() == 0) {
message = Messages.resources_nameEmpty;
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
char[] chars = OS.INVALID_RESOURCE_CHARACTERS;
for (char c : chars)
if (segment.indexOf(c) != -1) {
message = NLS.bind(Messages.resources_invalidCharInName, String.valueOf(c), segment);
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
if (!OS.isNameValid(segment)) {
message = NLS.bind(Messages.resources_invalidName, segment);
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
return Status.OK_STATUS;
}
public IStatus validatePath(IPath path, int type, boolean lastSegmentOnly) {
String message;
if (path == null) {
message = Messages.resources_pathNull;
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
if (path.getDevice() != null) {
message = NLS.bind(Messages.resources_invalidCharInPath, String.valueOf(IPath.DEVICE_SEPARATOR), path);
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
if (path.isRoot()) {
message = Messages.resources_invalidRoot;
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
if (!path.isAbsolute()) {
message = NLS.bind(Messages.resources_mustBeAbsolute, path);
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
int numberOfSegments = path.segmentCount();
if ((type & IResource.PROJECT) != 0) {
if (numberOfSegments == ICoreConstants.PROJECT_SEGMENT_LENGTH) {
return validateName(path.segment(0), IResource.PROJECT);
} else if (type == IResource.PROJECT) {
message = NLS.bind(Messages.resources_projectPath, path);
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
}
if ((type & (IResource.FILE | IResource.FOLDER)) != 0) {
if (numberOfSegments < ICoreConstants.MINIMUM_FILE_SEGMENT_LENGTH) {
message = NLS.bind(Messages.resources_resourcePath, path);
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
int fileFolderType = type &= ~IResource.PROJECT;
int segmentCount = path.segmentCount();
if (lastSegmentOnly)
return validateName(path.segment(segmentCount - 1), fileFolderType);
IStatus status = validateName(path.segment(0), IResource.PROJECT);
if (!status.isOK())
return status;
for (int i = 1; i < segmentCount; i++) {
status = validateName(path.segment(i), fileFolderType);
if (!status.isOK())
return status;
}
return Status.OK_STATUS;
}
message = NLS.bind(Messages.resources_invalidPath, path);
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
public IStatus validatePath(String path, int type) {
if (path == null) {
String message = Messages.resources_pathNull;
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
return validatePath(Path.fromOSString(path), type, false);
}
public IStatus validateProjectLocation(IProject context, IPath unresolvedLocation) {
if (unresolvedLocation == null)
return validateProjectLocationURI(context, null);
IPath location;
if (context != null)
location = context.getPathVariableManager().resolvePath(unresolvedLocation);
else
location = workspace.getPathVariableManager().resolvePath(unresolvedLocation);
if (!location.isAbsolute()) {
String message;
if (location.segmentCount() > 0)
message = NLS.bind(Messages.pathvar_undefined, location.toString(), location.segment(0));
else
message = Messages.links_noPath;
return new ResourceStatus(IResourceStatus.VARIABLE_NOT_DEFINED, null, message);
}
return validateProjectLocationURI(context, URIUtil.toURI(location));
}
public IStatus validateProjectLocationURI(IProject context, URI unresolvedLocation) {
if (context == null && unresolvedLocation == null)
throw new IllegalArgumentException("Either a project or a location must be provided");
boolean isMetadataLocation = false;
if (unresolvedLocation != null) {
if (URIUtil.equals(unresolvedLocation, URIUtil.toURI(Platform.getLocation().addTrailingSeparator().append(LocalMetaArea.F_METADATA)))) {
isMetadataLocation = true;
}
} else if (context != null && context.getName().equals(LocalMetaArea.F_METADATA)) {
isMetadataLocation = true;
}
String message;
if (isMetadataLocation) {
message = NLS.bind(Messages.resources_invalidPath, toString(URIUtil.toURI(Platform.getLocation().addTrailingSeparator().append(LocalMetaArea.F_METADATA))));
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
if (unresolvedLocation == null)
return Status.OK_STATUS;
URI location;
if (context != null)
location = context.getPathVariableManager().resolveURI(unresolvedLocation);
else
location = workspace.getPathVariableManager().resolveURI(unresolvedLocation);
IStatus result = validateSegments(location);
if (!result.isOK())
return result;
result = validateAbsolute(location, true);
if (!result.isOK())
return result;
try {
EFS.getFileSystem(location.getScheme());
} catch (CoreException e) {
return e.getStatus();
}
if (location.getScheme().equals(EFS.SCHEME_FILE)) {
IPath locationPath = URIUtil.toPath(location);
IPath defaultDefaultLocation = workspace.getRoot().getLocation();
if (FileUtil.isPrefixOf(locationPath, defaultDefaultLocation)) {
message = NLS.bind(Messages.resources_overlapWorkspace, toString(location), defaultDefaultLocation.toOSString());
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
IPath parentPath = locationPath.removeLastSegments(1);
if (FileUtil.isPrefixOf(parentPath, defaultDefaultLocation) && FileUtil.isPrefixOf(defaultDefaultLocation, parentPath) && (context == null || !locationPath.equals(defaultDefaultLocation.append(context.getName())))) {
message = NLS.bind(Messages.resources_overlapProject, toString(location), locationPath.lastSegment());
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
}
IProject[] projects = workspace.getRoot().getProjects(IContainer.INCLUDE_HIDDEN);
for (IProject project : projects) {
URI testLocation = project.getLocationURI();
if (context != null && project.equals(context)) {
if (URIUtil.equals(testLocation, location))
continue;
if (!FileUtil.isPrefixOf(testLocation, location))
continue;
} else if (!URIUtil.equals(testLocation, location)) {
continue;
}
message = NLS.bind(Messages.resources_overlapProject, toString(location), project.getName());
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
if (context != null && context.exists() && context.isOpen()) {
IResource[] children = null;
try {
children = context.members();
} catch (CoreException e) {
}
if (children != null) {
for (IResource child : children) {
if (child.isLinked()) {
URI testLocation = child.getLocationURI();
if (testLocation != null && FileUtil.isPrefixOf(testLocation, location)) {
message = NLS.bind(Messages.links_locationOverlapsLink, toString(location));
return new ResourceStatus(IResourceStatus.OVERLAPPING_LOCATION, context.getFullPath(), message);
}
}
}
}
}
return Status.OK_STATUS;
}
private IStatus validateSegments(URI location) {
if (EFS.SCHEME_FILE.equals(location.getScheme())) {
IPath pathPart = new Path(location.getSchemeSpecificPart());
int segmentCount = pathPart.segmentCount();
for (int i = 0; i < segmentCount; i++) {
IStatus result = validateName(pathPart.segment(i), IResource.PROJECT);
if (!result.isOK())
return result;
}
}
return Status.OK_STATUS;
}
}