/******************************************************************************* * Copyright (c) 2011, 2015 Wind River Systems, Inc. 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: * Wind River Systems - initial API and implementation * William Chen (Wind River)- [345387] Open the remote files with a proper editor * William Chen (Wind River)- [345552] Edit the remote files with a proper editor *******************************************************************************/ package org.eclipse.tcf.te.tcf.filesystem.core.internal.utils; import java.io.File; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.ISafeRunnable; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.osgi.util.NLS; import org.eclipse.tcf.te.tcf.filesystem.core.activator.CorePlugin; import org.eclipse.tcf.te.tcf.filesystem.core.interfaces.runtime.IFSTreeNode; import org.eclipse.tcf.te.tcf.filesystem.core.internal.FSTreeNode; import org.eclipse.tcf.te.tcf.filesystem.core.nls.Messages; /** * The local file system cache used to manage the temporary files downloaded from a remote file * system. */ public class CacheManager { public static final char PATH_ESCAPE_CHAR = '$'; /** * Get the local path of a node's cached file. * <p> * The preferred location is within the plugin's state location, in example * <code><state location>agent_<hashcode_of_peerId>/remote/path/to/the/file...</code>. * <p> * If the plug-in is loaded in a RCP workspace-less environment, the fall back strategy is to * use the users home directory. * * @param node The file/folder node. * @return The local path of the node's cached file. */ public static IPath getCachePath(IFSTreeNode node) { File location = getCacheRoot(); String agentId = node.getRuntimeModel().getPeerNode().getPeerId(); // Use Math.abs to avoid negative hash value. String agent = agentId.replace(':', PATH_ESCAPE_CHAR); IPath agentDir = new Path(location.getAbsolutePath()).append(agent); File agentDirFile = agentDir.toFile(); mkdirChecked(agentDirFile); return appendNodePath(agentDir, node); } /** * Check and make a directory if it does not exist. Record the failure message if making fails. * * @param file The file to be deleted. */ static void mkdirChecked(final File dir) { if (!dir.exists()) { SafeRunner.run(new ISafeRunnable() { @Override public void run() throws Exception { if (!dir.mkdirs()) { throw new Exception(NLS.bind(Messages.CacheManager_MkdirFailed, dir .getAbsolutePath())); } } @Override public void handleException(Throwable exception) { // Ignore on purpose } }); } } /** * Check if the file exists and set its read-only attribute if it does. Record the failure * message if it fails. * * @param file The file to be set. */ static void setReadOnlyChecked(final File file) { if (file.exists()) { SafeRunner.run(new ISafeRunnable() { @Override public void run() throws Exception { if (!file.setReadOnly()) { throw new Exception(NLS.bind(Messages.CacheManager_SetReadOnlyFailed, file .getAbsolutePath())); } } @Override public void handleException(Throwable exception) { // Ignore on purpose } }); } } /** * Get the local file of the specified node. * * <p> * The preferred location is within the plugin's state location, in example * <code><state location>agent_<hashcode_of_peerId>/remote/path/to/the/file...</code>. * <p> * If the plug-in is loaded in a RCP workspace-less environment, the fall back strategy is to * use the users home directory. * * @param node The file/folder node. * @return The file object of the node's local cache. */ public static File getCacheFile(IFSTreeNode node) { return getCachePath(node).toFile(); } /** * Get the cache file system's root directory on the local host's file system. * * @return The root folder's location of the cache file system. */ public static File getCacheRoot() { File location; try { location = CorePlugin.getDefault().getStateLocation().toFile(); } catch (IllegalStateException e) { // An RCP workspace-less environment (-data @none) location = new File(System.getProperty("user.home"), ".tcf"); //$NON-NLS-1$ //$NON-NLS-2$ location = new File(location, "fs"); //$NON-NLS-1$ } // Create the location if it not exist mkdirChecked(location); return location; } /** * Append the path with the specified node's context path. * * @param path The path to be appended. * @param node The file/folder node. * @return The path to the node. */ private static IPath appendNodePath(IPath path, IFSTreeNode node) { if (!node.isRootDirectory() && node.getParent() != null) { path = appendNodePath(path, node.getParent()); return appendPathSegment(node, path, node.getName()); } String name = node.getName(); if (node.isWindowsNode()) { name = name.replace('\\', '/'); } name = name.replace(':', PATH_ESCAPE_CHAR); if (name.endsWith("/")) //$NON-NLS-1$ name = name.substring(0, name.length()-1); return appendPathSegment(node, path, name); } /** * Append the path with the segment "name". Create a directory if the node is a directory which * does not yet exist. * * @param node The file/folder node. * @param path The path to appended. * @param name The segment's name. * @return The path with the segment "name" appended. */ private static IPath appendPathSegment(IFSTreeNode node, IPath path, String name) { IPath newPath = path.append(name); File newFile = newPath.toFile(); if (node.isDirectory()) { mkdirChecked(newFile); } return newPath; } public static void clearCache(FSTreeNode source) { if (source != null) { File cache = getCacheFile(source); if (cache.exists()) deleteFileOrDir(cache); } } private static boolean deleteFileOrDir(File file) { File[] children = file.listFiles(); boolean ok = true; if (children != null) { for (File child : children) { if (!deleteFileOrDir(child)) { ok = false; } } } return ok && file.delete(); } }