/******************************************************************************* * Copyright (c) 2005, 2015 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 *******************************************************************************/ package org.eclipse.core.internal.filesystem; import java.io.File; import java.io.IOException; import org.eclipse.core.filesystem.*; import org.eclipse.core.filesystem.provider.FileStore; import org.eclipse.core.internal.filesystem.local.LocalFile; import org.eclipse.core.runtime.*; import org.eclipse.osgi.service.environment.Constants; import org.eclipse.osgi.util.NLS; /** * An instance of this class represents a directory on disk where cached * files can be stored. Files in the cache expire on VM exit. */ public class FileCache { private static final String CACHE_DIR_NAME = "filecache";//$NON-NLS-1$ /** * Thread safety for lazy instantiation of the cache */ private static final Object creationLock = new Object(); /** * Cached constant indicating if the current OS is Mac OSX */ static final boolean MACOSX = FileCache.getOS().equals(Constants.OS_MACOSX); /** * The singleton file cache instance. */ private static FileCache instance = null; private File cacheDir; /** * Public accessor to obtain the singleton file cache instance, * creating the cache lazily if necessary. * @return The file cache instance * @throws CoreException */ public static FileCache getCache() throws CoreException { synchronized (creationLock) { if (instance == null) instance = new FileCache(); return instance; } } /** * Creates a new file cache. * * @throws CoreException If the file cache could not be created */ private FileCache() throws CoreException { IPath location = Activator.getCacheLocation(); File cacheParent = new File(location.toFile(), CACHE_DIR_NAME); cleanOldCache(cacheParent); cacheParent.mkdirs(); //make sure we have a unique non-existing cache directory cacheDir = getUniqueDirectory(cacheParent, true); } /** * Implements {@link FileStore#toLocalFile(int, IProgressMonitor)} * @param source * @param monitor * @return The cached file * @throws CoreException */ public java.io.File cache(IFileStore source, IProgressMonitor monitor) throws CoreException { try { SubMonitor subMonitor = SubMonitor.convert(monitor, NLS.bind(Messages.copying, toString()), 3); IFileInfo myInfo = source.fetchInfo(EFS.NONE, subMonitor.newChild(1)); if (!myInfo.exists()) return new File(cacheDir, "Non-Existent-" + System.currentTimeMillis()); //$NON-NLS-1$ File result; if (myInfo.isDirectory()) { result = getUniqueDirectory(cacheDir, false); } else { result = File.createTempFile(source.getFileSystem().getScheme(), "efs", cacheDir); //$NON-NLS-1$ } subMonitor.worked(1); IFileStore resultStore = new LocalFile(result); source.copy(resultStore, EFS.OVERWRITE, subMonitor.newChild(1)); result.deleteOnExit(); return result; } catch (IOException e) { Policy.error(EFS.ERROR_WRITE, NLS.bind(Messages.couldNotWrite, toString())); return null; // Can't get here } } /** * Performs initial cleanup of any old cached state left over from previous * sessions. */ private void cleanOldCache(File cacheParent) throws CoreException { //clear any old cache - this could be moved to a background thread if (MACOSX) { // fix for bug 323833: clear the immutable flag before old cache deletion on MacOS clearImmutableFlag(cacheParent); } new LocalFile(cacheParent).delete(EFS.NONE, null); } private void clearImmutableFlag(File target) { if (!target.exists()) { return; } if (target.isDirectory()) { File[] children = target.listFiles(); if (children != null) { for (int i = 0, imax = children.length; i < imax; i++) { clearImmutableFlag(children[i]); } } } else { LocalFile lfile = new LocalFile(target); try { IFileInfo info = lfile.fetchInfo(EFS.NONE, null); if (info.getAttribute(EFS.ATTRIBUTE_IMMUTABLE)) { info.setAttribute(EFS.ATTRIBUTE_IMMUTABLE, false); lfile.putInfo(info, EFS.SET_ATTRIBUTES, null); } } catch (CoreException e) { // ignore and continue since failed deletions will be reported by LocalFile.delete() } } } /** * Returns the current OS. This is equivalent to Platform.getOS(), but * is tolerant of the platform runtime not being present. */ static String getOS() { return System.getProperty("osgi.os", ""); //$NON-NLS-1$ //$NON-NLS-2$ } /** * Returns a new unique directory in the given parent directory. * * @param parent * @param create <code>true</code> if the directory should * be created, and false otherwise. * @return The unique directory */ private File getUniqueDirectory(File parent, boolean create) { File dir; long i = 0; //find an unused directory name do { dir = new File(parent, Long.toString(System.currentTimeMillis() + i++)); } while (dir.exists()); if (create) dir.mkdir(); return dir; } }