/******************************************************************************* * Copyright (c) 2005, 2014 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 * Serge Beauchamp (Freescale Semiconductor) - [229633] Project Path Variable Support * Sergey Prigogin (Google) - [338010] Resource.createLink() does not preserve symbolic links *******************************************************************************/ package org.eclipse.core.internal.localstore; import java.io.File; import java.net.URI; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.internal.utils.FileUtil; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; /** * Represents the root of a file system that is connected to the workspace. * A file system can be rooted on any resource. */ public class FileStoreRoot { private int chop; /** * When a root is changed, the old root object is marked invalid * so that other resources with a cache of the root will know they need to update. */ private boolean isValid = true; /** * If this root represents a resource in the local file system, this path * represents the root location. This value is null if the root represents * a non-local file system */ private IPath localRoot; /** * Canonicalized version of localRoot. Initialized lazily. * @see FileUtil#canonicalPath(IPath) */ private IPath canonicalLocalRoot; private URI root; /** * Canonicalized version of root. Initialized lazily. * @see FileUtil#canonicalURI(URI) */ private URI canonicalRoot; /** * Defines the root of a file system within the workspace tree. * @param rootURI The virtual file representing the root of the file * system that has been mounted * @param workspacePath The workspace path at which this file * system has been mounted */ FileStoreRoot(URI rootURI, IPath workspacePath) { Assert.isNotNull(rootURI); Assert.isNotNull(workspacePath); this.root = rootURI; this.chop = workspacePath.segmentCount(); this.localRoot = toLocalPath(root); } private IPathVariableManager getManager(IPath workspacePath) { IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); IResource resource = workspaceRoot.findMember(workspacePath); if (resource != null) return resource.getPathVariableManager(); return workspaceRoot.getFile(workspacePath).getPathVariableManager(); } /** * Returns the resolved, absolute file system location of the resource * corresponding to the given workspace path, or null if none could * be computed. No canonicalization is applied to the returned URI. */ public URI computeURI(IPath workspacePath) { return computeURI(workspacePath, false); } /** * Returns the resolved, absolute file system location of the resource * corresponding to the given workspace path, or null if none could * be computed. * * @param workspacePath the workspace path to compute the URL for * @param canonical if {@code true}, the prefix of the path of the returned URI * corresponding to this root will be canonicalized */ public URI computeURI(IPath workspacePath, boolean canonical) { IPath childPath = workspacePath.removeFirstSegments(chop); URI rootURI = canonical ? getCanonicalRoot() : root; rootURI = getManager(workspacePath).resolveURI(rootURI); if (childPath.segmentCount() == 0) return rootURI; try { return EFS.getStore(rootURI).getFileStore(childPath).toURI(); } catch (CoreException e) { return null; } } /** * Creates an IFileStore for a given workspace path. The prefix of the path of * the returned IFileStore corresponding to this root is canonicalized. * @exception CoreException If the file system for that resource is undefined */ IFileStore createStore(IPath workspacePath, IResource resource) throws CoreException { IPath childPath = workspacePath.removeFirstSegments(chop); // For a linked resource itself we have to use its root, but for its children we prefer // to use the canonical root since it provides for faster file system access. // See http://bugs.eclipse.org/507084 final URI uri = resource.getPathVariableManager().resolveURI(resource.isLinked() ? root : getCanonicalRoot()); if (!uri.isAbsolute()) { // Handles case where resource location cannot be resolved such as // unresolved path variable or invalid file system scheme. return EFS.getNullFileSystem().getStore(workspacePath); } IFileStore rootStore = EFS.getStore(uri); if (childPath.segmentCount() == 0) return rootStore; return rootStore.getFileStore(childPath); } boolean isValid() { return isValid; } /** * Returns the resolved, absolute file system location of the given resource. * Returns null if the location could not be resolved. No canonicalization * is applied to the returned path. * * @param workspacePath the workspace path of the resource * @param resource the resource itself */ IPath localLocation(IPath workspacePath, IResource resource) { return localLocation(workspacePath, resource, false); } /** * Returns the resolved, absolute file system location of the given resource. * Returns null if the location could not be resolved. * * @param workspacePath the workspace path of the resource * @param resource the resource itself * @param canonical if {@code true}, the prefix of the returned path corresponding * to this root will be canonicalized */ IPath localLocation(IPath workspacePath, IResource resource, boolean canonical) { if (localRoot == null) return null; IPath rootPath = canonical ? getCanonicalLocalRoot() : localRoot; IPath location; if (workspacePath.segmentCount() <= chop) location = rootPath; else location = rootPath.append(workspacePath.removeFirstSegments(chop)); location = resource.getPathVariableManager().resolvePath(location); // if path is still relative then path variable could not be resolved // if path is null, it means path variable refers to a non-local filesystem if (location == null || !location.isAbsolute()) return null; return location; } void setValid(boolean value) { this.isValid = value; } /** * Returns the local path for the given URI, or null if not possible. */ private IPath toLocalPath(URI uri) { try { final File localFile = EFS.getStore(uri).toLocalFile(EFS.NONE, null); return localFile == null ? null : new Path(localFile.getAbsolutePath()); } catch (CoreException e) { return FileUtil.toPath(uri); } } private synchronized IPath getCanonicalLocalRoot() { if (canonicalLocalRoot == null && localRoot != null) { canonicalLocalRoot = FileUtil.canonicalPath(localRoot); } return canonicalLocalRoot; } private synchronized URI getCanonicalRoot() { if (canonicalRoot == null) { canonicalRoot = FileUtil.canonicalURI(root); } return canonicalRoot; } }