blob: dff06a167a106ee37d0ad054747e5cae1a0a37b5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* 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 If the file cache could not be created
*/
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 = FileSystemAccess.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 source data to cache on disk
* @param monitor
* monitor to indicate progress and receive cancellation
* @return The cached file
* @throws CoreException on errors using the source filestore or writing the cache file
*/
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 (File element : children) {
clearImmutableFlag(element);
}
}
} 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;
}
}